All files / sdk/utils error.ts

40.32% Statements 25/62
34.54% Branches 19/55
60% Functions 3/5
40.32% Lines 25/62

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 16016x 16x 16x   16x   16x     1x             1x               1x               1x   1x                         1x 1x             1x                                                                                                               1x 1x 1x   1x   1x 1x                                                               4x 4x   4x 4x 4x   4x    
import { SDK_ERROR_CODES, BASE_ERROR_CODE_INFO, BE_STATUS_CODE_TO_SDK_ERROR_CODES } from "./errors/src/constants";
import { ComposioError } from "./errors/src/composioError";
import { generateMetadataFromAxiosError, getAPIErrorDetails } from "./errors/src/formatter";
import { AxiosError } from "axios";
import { ZodError } from "zod";
 
export class CEG {
    
    static handleAllError(error: unknown, shouldThrow: boolean = false) {
        Iif(error instanceof ComposioError) {
            Iif(shouldThrow) {
               throw error;
            }
            return error;
        }
 
        Iif (!(error instanceof Error)) {
            const error = new Error("Passed error is not an instance of Error");
            Iif(shouldThrow) {
               throw error;
            }
            return error;
        }
 
        Iif(error instanceof ZodError) {
            const zodError = this.returnZodError(error);
            Iif(shouldThrow) {
               throw zodError;
            }
            return zodError;
        }
 
        const isAxiosError = (error as AxiosError).isAxiosError;
 
        Iif (!isAxiosError) {
            const customError = this.getCustomError(SDK_ERROR_CODES.COMMON.UNKNOWN, {
                message: error.message,
                description: "",
                possibleFix: "Please check error message and stack trace",
                originalError: error,
                metadata: {}
            });
            Iif(shouldThrow) {
               throw customError;
            }
            return customError;
        } else {
            const isResponseNotPresent = !('response' in error);    
            Iif(isResponseNotPresent) {
                const nonResponseError = this.handleNonResponseAxiosError(error as AxiosError);
                Iif(shouldThrow) {
                   throw nonResponseError;
                }
                return nonResponseError;
            }
            const apiError = this.throwAPIError(error as AxiosError);
            Iif(shouldThrow) {
               throw apiError;
            }
            return apiError;
        }
    }
 
    private static handleNonResponseAxiosError(error: AxiosError) {
        const fullUrl = (error.config?.baseURL || "") + (error.config?.url || "");
        const metadata = generateMetadataFromAxiosError(error);
 
        Iif (error.code === "ECONNREFUSED") {
            throw new ComposioError(
                SDK_ERROR_CODES.COMMON.BASE_URL_NOT_REACHABLE,
                `ECONNREFUSED for ${fullUrl}`,
                "",
                "Make sure:\n1. The base URL is correct and is accessible\n2. Your network connection is stable\n3. There are no firewall rules blocking the connection",
                metadata,
                error
            );
        }
 
        Iif ( error.code === "ETIMEDOUT") {
            throw new ComposioError(
                SDK_ERROR_CODES.COMMON.REQUEST_TIMEOUT,
                `ECONNABORTED for ${fullUrl}`,
                `Request to ${fullUrl} timed out after the configured timeout period. This could be due to slow network conditions, server performance issues, or the request being too large. Error code: ECONNABORTED`,
                "Try:\n1. Checking your network speed and stability\n2. Increasing the request timeout setting if needed\n3. Breaking up large requests into smaller chunks\n4. Retrying the request when network conditions improve\n5. Contact tech@composio.dev if the issue persists",
                metadata,
                error
            );
        }
 
        Iif(error.code === "ECONNABORTED") {
           throw new ComposioError(
                SDK_ERROR_CODES.COMMON.REQUEST_ABORTED,
                error.message,
                "The request was aborted due to a timeout or other network-related issues. This could be due to network instability, server issues, or the request being too large. Error code: ECONNABORTED",
                "Try:\n1. Checking your network speed and stability\n2. Increasing the request timeout setting if needed\n3. Breaking up large requests into smaller chunks\n4. Retrying the request when network conditions improve\n5. Contact tech@composio.dev if the issue persists",
                metadata,
                error
            );
        }
 
        throw new ComposioError(
            SDK_ERROR_CODES.COMMON.UNKNOWN,
            error.message,
            "",
            "Please contact tech@composio.dev with the error details.",
            metadata,
            error
        );
    }
 
    static throwAPIError(error: AxiosError) {
        const statusCode = error?.response?.status || null;
        const errorCode = statusCode ? BE_STATUS_CODE_TO_SDK_ERROR_CODES[statusCode] || SDK_ERROR_CODES.BACKEND.UNKNOWN : SDK_ERROR_CODES.BACKEND.UNKNOWN;
        const predefinedError = BASE_ERROR_CODE_INFO[errorCode];
 
        const errorDetails = getAPIErrorDetails(errorCode, error, predefinedError);
   
        const metadata = generateMetadataFromAxiosError(error);
        throw new ComposioError(errorCode, errorDetails.message, errorDetails.description, errorDetails.possibleFix, metadata, error)
    }
 
    static returnZodError(error: ZodError) {
        const errorCode = SDK_ERROR_CODES.COMMON.INVALID_PARAMS_PASSED;
        const errorMessage = error.message;
        const errorDescription = "The parameters passed are invalid";
        const possibleFix = "Please check the metadata.issues for more details";
        const metadata = {
            issues: error.issues
        };
        
        return new ComposioError(errorCode, errorMessage, errorDescription, possibleFix, metadata, error);
    }
 
    static getCustomError(messageCode: string, {
        message,
        type,
        subtype,
        description,
        possibleFix,
        originalError,
        metadata
    }: {
        type?: string;
        subtype?: string;
        message?: string;
        description?: string;
        possibleFix?: string;
        originalError?: unknown;
        metadata?: Record<string, any>;
    }): never {
        const finalErrorCode = !!messageCode ? messageCode : `${type}::${subtype}`;
        const errorDetails = BASE_ERROR_CODE_INFO[finalErrorCode] || BASE_ERROR_CODE_INFO.UNKNOWN;
 
        const finalMessage = message || errorDetails.message || "";
        const finalDescription = description || errorDetails.description || undefined;
        const finalPossibleFix = possibleFix || errorDetails.possibleFix || "";
 
        throw new ComposioError(messageCode, finalMessage, finalDescription, finalPossibleFix, metadata, originalError);
    }
}