2022-07-24 08:25:01 -07:00
|
|
|
/* eslint-disable @typescript-eslint/naming-convention */
|
2023-07-31 02:00:48 -07:00
|
|
|
|
2021-04-16 09:33:36 -07:00
|
|
|
import { parseString } from 'xml2js';
|
2023-07-12 03:31:32 -07:00
|
|
|
import { removeCircularRefs, isTraversableObject } from './utils';
|
2023-01-27 05:56:56 -08:00
|
|
|
import type { IDataObject, INode, IStatusCodeMessages, JsonObject } from './Interfaces';
|
2021-04-16 09:33:36 -07:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Top-level properties where an error message can be found in an API response.
|
|
|
|
*/
|
|
|
|
const ERROR_MESSAGE_PROPERTIES = [
|
:sparkles: Add Onfleet Node & Trigger (#2845)
* feat: added Onfleet nodes
Added Onfleet nodes for working with different endpoints like:
organizations, administrators, workers, hubs, teams, destinations, recipients,
containers and webhooks.
* style: fixed typos, arrays uniformity, unnecesary files
* refactor: changed add to create in comments and labels
* feat: added name field to onfleet trigger node
* feat: added team endpoints to onfleet node
Added team auto-dispatch and driver time estimate endpoints to Onfleet
node
* style: remove dots in descriptions and fixed some typos
* feat: added fixes according to comments made on the n8n PR
added new fixed collections, refactored the code according to comments
made on the n8n pr
* fix: fixed recipient and destination cretion
* docs: added docstrings for format some functions
added docstrings for new functions addded for formatting the destination
and recipient objects
* style: formatting the code according to n8n nodelinter
* fix: typos and better descriptions
* [INT-510] n8n: Address additional problems from n8n code review (#5)
* Fixed some error creating a worker, moving some fields under additional fields collection
* Fixed returned values for delete operations, making some changes for style code
* Added operational error since required property is not working for dateTime fields
* :zap: Improvements to #2593
* :zap: Improvements
* :bug: Fix issue with wrong interface
* :zap: Improvements
* :zap: Improvements
* :zap: Minor improvement
Co-authored-by: Santiago Botero Ruiz <santiago.botero@devsavant.ai>
Co-authored-by: ilsemaj <james.li.upenn@gmail.com>
Co-authored-by: Santiago Botero Ruiz <39206812+YokySantiago@users.noreply.github.com>
Co-authored-by: Jan Oberhauser <jan.oberhauser@gmail.com>
2022-02-28 00:48:17 -08:00
|
|
|
'cause',
|
2021-04-16 09:33:36 -07:00
|
|
|
'error',
|
|
|
|
'message',
|
|
|
|
'Message',
|
|
|
|
'msg',
|
|
|
|
'messages',
|
|
|
|
'description',
|
|
|
|
'reason',
|
|
|
|
'detail',
|
|
|
|
'details',
|
|
|
|
'errors',
|
|
|
|
'errorMessage',
|
|
|
|
'errorMessages',
|
|
|
|
'ErrorMessage',
|
|
|
|
'error_message',
|
|
|
|
'_error_message',
|
|
|
|
'errorDescription',
|
|
|
|
'error_description',
|
|
|
|
'error_summary',
|
|
|
|
'title',
|
|
|
|
'text',
|
|
|
|
'field',
|
|
|
|
'err',
|
|
|
|
'type',
|
|
|
|
];
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Top-level properties where an HTTP error code can be found in an API response.
|
|
|
|
*/
|
|
|
|
const ERROR_STATUS_PROPERTIES = [
|
|
|
|
'statusCode',
|
|
|
|
'status',
|
|
|
|
'code',
|
|
|
|
'status_code',
|
|
|
|
'errorCode',
|
|
|
|
'error_code',
|
|
|
|
];
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Properties where a nested object can be found in an API response.
|
|
|
|
*/
|
|
|
|
const ERROR_NESTING_PROPERTIES = ['error', 'err', 'response', 'body', 'data'];
|
|
|
|
|
2023-08-14 12:12:35 -07:00
|
|
|
/**
|
|
|
|
* Descriptive messages for common errors.
|
|
|
|
*/
|
|
|
|
const COMMON_ERRORS: IDataObject = {
|
|
|
|
// nodeJS errors
|
|
|
|
ECONNREFUSED: 'The service refused the connection - perhaps it is offline',
|
|
|
|
ECONNRESET:
|
|
|
|
'The connection to the server wes closed unexpectedly, perhaps it is offline. You can retry request immidiately or wait and retry later.',
|
|
|
|
ENOTFOUND:
|
|
|
|
'The connection cannot be established, this usually occurs due to an incorrect host(domain) value',
|
|
|
|
ETIMEDOUT:
|
|
|
|
"The connection timed out, consider setting 'Retry on Fail' option in the node settings",
|
|
|
|
ERRADDRINUSE:
|
|
|
|
'The port is already occupied by some other application, if possible change the port or kill the application that is using it',
|
|
|
|
EADDRNOTAVAIL: 'The address is not available, ensure that you have the right IP address',
|
|
|
|
ECONNABORTED: 'The connection was aborted, perhaps the server is offline',
|
|
|
|
EHOSTUNREACH: 'The host is unreachable, perhaps the server is offline',
|
|
|
|
EAI_AGAIN: 'The DNS server returned an error, perhaps the server is offline',
|
|
|
|
ENOENT: 'The file or directory does not exist',
|
|
|
|
EISDIR: 'The file path expected but a given path is a directory',
|
|
|
|
ENOTDIR: 'The directory path expected but a given path is a file',
|
|
|
|
EACCES: 'Forbidden by access permissions, make sure you have the right permissions',
|
|
|
|
EEXIST: 'The file or directory already exists',
|
|
|
|
EPERM: 'Operation not permitted, make sure you have the right permissions',
|
|
|
|
// other errors
|
|
|
|
GETADDRINFO: 'The server closed the connection unexpectedly',
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Descriptive messages for common HTTP status codes
|
|
|
|
* this is used by NodeApiError class
|
|
|
|
*/
|
|
|
|
const STATUS_CODE_MESSAGES: IStatusCodeMessages = {
|
|
|
|
'4XX': 'Your request is invalid or could not be processed by the service',
|
|
|
|
'400': 'Bad request - please check your parameters',
|
|
|
|
'401': 'Authorization failed - please check your credentials',
|
|
|
|
'402': 'Payment required - perhaps check your payment details?',
|
|
|
|
'403': 'Forbidden - perhaps check your credentials?',
|
|
|
|
'404': 'The resource you are requesting could not be found',
|
|
|
|
'405': 'Method not allowed - please check you are using the right HTTP method',
|
2023-09-28 07:00:45 -07:00
|
|
|
'429': 'The service is receiving too many requests from you',
|
2023-08-14 12:12:35 -07:00
|
|
|
|
|
|
|
'5XX': 'The service failed to process your request',
|
|
|
|
'500': 'The service was not able to process your request',
|
|
|
|
'502': 'Bad gateway - the service failed to handle your request',
|
|
|
|
'503':
|
|
|
|
'Service unavailable - try again later or consider setting this node to retry automatically (in the node settings)',
|
|
|
|
'504': 'Gateway timed out - perhaps try again later?',
|
|
|
|
};
|
|
|
|
|
|
|
|
const UNKNOWN_ERROR_MESSAGE = 'UNKNOWN ERROR - check the detailed error for more information';
|
|
|
|
const UNKNOWN_ERROR_MESSAGE_CRED = 'UNKNOWN ERROR';
|
|
|
|
|
2023-09-27 07:57:52 -07:00
|
|
|
export type Severity = 'warning' | 'error';
|
2023-08-14 12:12:35 -07:00
|
|
|
|
2022-10-26 02:55:39 -07:00
|
|
|
interface ExecutionBaseErrorOptions {
|
|
|
|
cause?: Error | JsonObject;
|
|
|
|
}
|
|
|
|
|
2023-08-14 12:12:35 -07:00
|
|
|
interface NodeOperationErrorOptions {
|
|
|
|
message?: string;
|
|
|
|
description?: string;
|
|
|
|
runIndex?: number;
|
|
|
|
itemIndex?: number;
|
|
|
|
severity?: Severity;
|
|
|
|
messageMapping?: { [key: string]: string }; // allows to pass custom mapping for error messages scoped to a node
|
|
|
|
}
|
|
|
|
|
|
|
|
interface NodeApiErrorOptions extends NodeOperationErrorOptions {
|
|
|
|
message?: string;
|
|
|
|
httpCode?: string;
|
|
|
|
parseXml?: boolean;
|
|
|
|
}
|
|
|
|
|
2022-06-03 08:25:07 -07:00
|
|
|
export abstract class ExecutionBaseError extends Error {
|
2021-04-16 09:33:36 -07:00
|
|
|
description: string | null | undefined;
|
2021-08-29 11:58:11 -07:00
|
|
|
|
2022-11-07 09:40:54 -08:00
|
|
|
cause: Error | JsonObject | undefined;
|
|
|
|
|
2021-04-16 09:33:36 -07:00
|
|
|
timestamp: number;
|
|
|
|
|
2022-06-03 08:25:07 -07:00
|
|
|
context: IDataObject = {};
|
|
|
|
|
2022-10-13 05:28:02 -07:00
|
|
|
lineNumber: number | undefined;
|
|
|
|
|
2023-09-27 07:57:52 -07:00
|
|
|
severity: Severity = 'error';
|
|
|
|
|
2022-10-26 02:55:39 -07:00
|
|
|
constructor(message: string, { cause }: ExecutionBaseErrorOptions) {
|
|
|
|
const options = cause instanceof Error ? { cause } : {};
|
|
|
|
super(message, options);
|
|
|
|
|
2021-04-16 09:33:36 -07:00
|
|
|
this.name = this.constructor.name;
|
|
|
|
this.timestamp = Date.now();
|
|
|
|
|
2022-10-26 02:55:39 -07:00
|
|
|
if (cause instanceof ExecutionBaseError) {
|
|
|
|
this.context = cause.context;
|
2022-11-07 09:40:54 -08:00
|
|
|
} else if (cause && !(cause instanceof Error)) {
|
|
|
|
this.cause = cause;
|
2022-06-03 08:25:07 -07:00
|
|
|
}
|
|
|
|
}
|
2023-02-17 01:54:07 -08:00
|
|
|
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
|
|
toJSON?(): any {
|
|
|
|
return {
|
|
|
|
message: this.message,
|
|
|
|
lineNumber: this.lineNumber,
|
|
|
|
timestamp: this.timestamp,
|
|
|
|
name: this.name,
|
|
|
|
description: this.description,
|
|
|
|
context: this.context,
|
|
|
|
cause: this.cause,
|
|
|
|
};
|
|
|
|
}
|
2022-06-03 08:25:07 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Base class for specific NodeError-types, with functionality for finding
|
|
|
|
* a value recursively inside an error object.
|
|
|
|
*/
|
2023-05-15 06:54:48 -07:00
|
|
|
export abstract class NodeError extends ExecutionBaseError {
|
2022-06-03 08:25:07 -07:00
|
|
|
node: INode;
|
|
|
|
|
|
|
|
constructor(node: INode, error: Error | JsonObject) {
|
2022-10-26 02:55:39 -07:00
|
|
|
const message = error instanceof Error ? error.message : '';
|
|
|
|
super(message, { cause: error });
|
2022-06-03 08:25:07 -07:00
|
|
|
this.node = node;
|
2021-04-16 09:33:36 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Finds property through exploration based on potential keys and traversal keys.
|
|
|
|
* Depth-first approach.
|
|
|
|
*
|
|
|
|
* This method iterates over `potentialKeys` and, if the value at the key is a
|
|
|
|
* truthy value, the type of the value is checked:
|
|
|
|
* (1) if a string or number, the value is returned as a string; or
|
|
|
|
* (2) if an array,
|
|
|
|
* its string or number elements are collected as a long string,
|
|
|
|
* its object elements are traversed recursively (restart this function
|
2021-06-12 08:15:23 -07:00
|
|
|
* with each object as a starting point), or
|
|
|
|
* (3) if it is an object, it traverses the object and nested ones recursively
|
|
|
|
* based on the `potentialKeys` and returns a string if found.
|
2021-04-16 09:33:36 -07:00
|
|
|
*
|
|
|
|
* If nothing found via `potentialKeys` this method iterates over `traversalKeys` and
|
|
|
|
* if the value at the key is a traversable object, it restarts with the object as the
|
|
|
|
* new starting point (recursion).
|
|
|
|
* If nothing found for any of the `traversalKeys`, exploration continues with remaining
|
|
|
|
* `traversalKeys`.
|
|
|
|
*
|
|
|
|
* Otherwise, if all the paths have been exhausted and no value is eligible, `null` is
|
|
|
|
* returned.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
protected findProperty(
|
2022-10-26 02:55:39 -07:00
|
|
|
jsonError: JsonObject,
|
2021-04-16 09:33:36 -07:00
|
|
|
potentialKeys: string[],
|
2021-06-12 08:15:23 -07:00
|
|
|
traversalKeys: string[] = [],
|
2021-04-16 09:33:36 -07:00
|
|
|
): string | null {
|
|
|
|
for (const key of potentialKeys) {
|
2022-10-26 02:55:39 -07:00
|
|
|
const value = jsonError[key];
|
2022-09-09 07:34:50 -07:00
|
|
|
if (value) {
|
|
|
|
if (typeof value === 'string') return value;
|
|
|
|
if (typeof value === 'number') return value.toString();
|
|
|
|
if (Array.isArray(value)) {
|
|
|
|
const resolvedErrors: string[] = value
|
2023-08-14 12:12:35 -07:00
|
|
|
// eslint-disable-next-line @typescript-eslint/no-shadow
|
2022-10-26 02:55:39 -07:00
|
|
|
.map((jsonError) => {
|
|
|
|
if (typeof jsonError === 'string') return jsonError;
|
|
|
|
if (typeof jsonError === 'number') return jsonError.toString();
|
2023-07-12 03:31:32 -07:00
|
|
|
if (isTraversableObject(jsonError)) {
|
2022-10-26 02:55:39 -07:00
|
|
|
return this.findProperty(jsonError, potentialKeys);
|
2021-04-16 09:33:36 -07:00
|
|
|
}
|
|
|
|
return null;
|
|
|
|
})
|
2022-09-09 07:34:50 -07:00
|
|
|
.filter((errorValue): errorValue is string => errorValue !== null);
|
2021-04-16 09:33:36 -07:00
|
|
|
|
|
|
|
if (resolvedErrors.length === 0) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
return resolvedErrors.join(' | ');
|
|
|
|
}
|
2023-07-12 03:31:32 -07:00
|
|
|
if (isTraversableObject(value)) {
|
2022-09-09 07:34:50 -07:00
|
|
|
const property = this.findProperty(value, potentialKeys);
|
2021-06-12 08:15:23 -07:00
|
|
|
if (property) {
|
|
|
|
return property;
|
|
|
|
}
|
|
|
|
}
|
2021-04-16 09:33:36 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (const key of traversalKeys) {
|
2022-10-26 02:55:39 -07:00
|
|
|
const value = jsonError[key];
|
2023-07-12 03:31:32 -07:00
|
|
|
if (isTraversableObject(value)) {
|
2022-09-09 07:34:50 -07:00
|
|
|
const property = this.findProperty(value, potentialKeys, traversalKeys);
|
2021-04-16 09:33:36 -07:00
|
|
|
if (property) {
|
|
|
|
return property;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2023-08-14 12:12:35 -07:00
|
|
|
/**
|
|
|
|
* Set descriptive error message if code is provided or if message contains any of the common errors,
|
|
|
|
* update description to include original message plus the description
|
|
|
|
*/
|
|
|
|
protected setDescriptiveErrorMessage(
|
|
|
|
message: string,
|
|
|
|
description: string | undefined | null,
|
|
|
|
code?: string | null,
|
|
|
|
messageMapping?: { [key: string]: string },
|
|
|
|
) {
|
|
|
|
let newMessage = message;
|
|
|
|
let newDescription = description as string;
|
|
|
|
|
|
|
|
if (messageMapping) {
|
|
|
|
for (const [mapKey, mapMessage] of Object.entries(messageMapping)) {
|
|
|
|
if ((message || '').toUpperCase().includes(mapKey.toUpperCase())) {
|
|
|
|
newMessage = mapMessage;
|
|
|
|
newDescription = this.updateDescription(message, description);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (newMessage !== message) {
|
|
|
|
return [newMessage, newDescription];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// if code is provided and it is in the list of common errors set the message and return early
|
|
|
|
if (code && COMMON_ERRORS[code.toUpperCase()]) {
|
|
|
|
newMessage = COMMON_ERRORS[code] as string;
|
|
|
|
newDescription = this.updateDescription(message, description);
|
|
|
|
return [newMessage, newDescription];
|
|
|
|
}
|
|
|
|
|
|
|
|
// check if message contains any of the common errors and set the message and description
|
|
|
|
for (const [errorCode, errorDescriptiveMessage] of Object.entries(COMMON_ERRORS)) {
|
|
|
|
if ((message || '').toUpperCase().includes(errorCode.toUpperCase())) {
|
|
|
|
newMessage = errorDescriptiveMessage as string;
|
|
|
|
newDescription = this.updateDescription(message, description);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return [newMessage, newDescription];
|
|
|
|
}
|
|
|
|
|
|
|
|
protected updateDescription(message: string, description: string | undefined | null) {
|
|
|
|
return `${message}${description ? ` - ${description}` : ''}`;
|
|
|
|
}
|
2022-10-26 02:55:39 -07:00
|
|
|
}
|
|
|
|
|
2021-04-16 09:33:36 -07:00
|
|
|
/**
|
|
|
|
* Class for instantiating an operational error, e.g. an invalid credentials error.
|
|
|
|
*/
|
|
|
|
export class NodeOperationError extends NodeError {
|
2022-10-13 05:28:02 -07:00
|
|
|
lineNumber: number | undefined;
|
|
|
|
|
2022-10-26 02:55:39 -07:00
|
|
|
constructor(node: INode, error: Error | string, options: NodeOperationErrorOptions = {}) {
|
2021-04-16 09:33:36 -07:00
|
|
|
if (typeof error === 'string') {
|
|
|
|
error = new Error(error);
|
|
|
|
}
|
|
|
|
super(node, error);
|
2021-08-31 01:49:55 -07:00
|
|
|
|
2023-05-15 06:54:48 -07:00
|
|
|
if (options.message) this.message = options.message;
|
|
|
|
if (options.severity) this.severity = options.severity;
|
2022-10-26 02:55:39 -07:00
|
|
|
this.description = options.description;
|
|
|
|
this.context.runIndex = options.runIndex;
|
|
|
|
this.context.itemIndex = options.itemIndex;
|
2021-04-16 09:33:36 -07:00
|
|
|
|
2023-08-14 12:12:35 -07:00
|
|
|
if (this.message === this.description) {
|
|
|
|
this.description = undefined;
|
|
|
|
}
|
2021-04-16 09:33:36 -07:00
|
|
|
|
2023-08-14 12:12:35 -07:00
|
|
|
[this.message, this.description] = this.setDescriptiveErrorMessage(
|
|
|
|
this.message,
|
|
|
|
this.description,
|
|
|
|
undefined,
|
|
|
|
options.messageMapping,
|
|
|
|
);
|
|
|
|
}
|
2022-10-26 02:55:39 -07:00
|
|
|
}
|
|
|
|
|
2021-04-16 09:33:36 -07:00
|
|
|
/**
|
|
|
|
* Class for instantiating an error in an API response, e.g. a 404 Not Found response,
|
|
|
|
* with an HTTP error code, an error message and a description.
|
|
|
|
*/
|
|
|
|
export class NodeApiError extends NodeError {
|
|
|
|
httpCode: string | null;
|
|
|
|
|
|
|
|
constructor(
|
|
|
|
node: INode,
|
2021-06-12 08:15:23 -07:00
|
|
|
error: JsonObject,
|
2023-05-15 06:54:48 -07:00
|
|
|
{
|
|
|
|
message,
|
|
|
|
description,
|
|
|
|
httpCode,
|
|
|
|
parseXml,
|
|
|
|
runIndex,
|
|
|
|
itemIndex,
|
|
|
|
severity,
|
2023-08-14 12:12:35 -07:00
|
|
|
messageMapping,
|
2023-05-15 06:54:48 -07:00
|
|
|
}: NodeApiErrorOptions = {},
|
2021-04-16 09:33:36 -07:00
|
|
|
) {
|
|
|
|
super(node, error);
|
2023-05-03 00:15:33 -07:00
|
|
|
|
2023-05-15 06:54:48 -07:00
|
|
|
if (severity) this.severity = severity;
|
|
|
|
else if (httpCode?.charAt(0) !== '5') this.severity = 'warning';
|
|
|
|
|
2023-08-14 12:12:35 -07:00
|
|
|
// only for request library error
|
2021-06-16 03:41:56 -07:00
|
|
|
if (error.error) {
|
2023-07-12 03:31:32 -07:00
|
|
|
removeCircularRefs(error.error as JsonObject);
|
2021-06-16 03:41:56 -07:00
|
|
|
}
|
2022-11-11 02:32:43 -08:00
|
|
|
|
2023-08-14 12:12:35 -07:00
|
|
|
// if not description provided, try to find it in the error object
|
|
|
|
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
2023-05-03 00:15:33 -07:00
|
|
|
if (!description && (error.description || (error?.reason as IDataObject)?.description)) {
|
2023-08-14 12:12:35 -07:00
|
|
|
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
|
|
|
this.description = (error.description ||
|
2023-05-03 00:15:33 -07:00
|
|
|
(error?.reason as IDataObject)?.description) as string;
|
|
|
|
}
|
|
|
|
|
2023-08-14 12:12:35 -07:00
|
|
|
// if not message provided, try to find it in the error object or set description as message
|
|
|
|
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
|
|
|
if (!message && (error.message || (error?.reason as IDataObject)?.message || description)) {
|
|
|
|
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
|
|
|
this.message = (error.message ||
|
|
|
|
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
|
|
|
(error?.reason as IDataObject)?.message ||
|
|
|
|
description) as string;
|
2023-05-03 00:15:33 -07:00
|
|
|
}
|
|
|
|
|
2022-06-17 21:39:49 -07:00
|
|
|
// if it's an error generated by axios
|
|
|
|
// look for descriptions in the response object
|
2022-11-11 02:32:43 -08:00
|
|
|
if (error.reason) {
|
|
|
|
const reason: IDataObject = error.reason as unknown as IDataObject;
|
2023-05-03 00:15:33 -07:00
|
|
|
|
2022-11-11 02:32:43 -08:00
|
|
|
if (reason.isAxiosError && reason.response) {
|
|
|
|
error = reason.response as JsonObject;
|
|
|
|
}
|
2022-06-17 21:39:49 -07:00
|
|
|
}
|
|
|
|
|
2023-08-14 12:12:35 -07:00
|
|
|
// set http code of this error
|
2023-05-03 00:15:33 -07:00
|
|
|
if (httpCode) {
|
|
|
|
this.httpCode = httpCode;
|
|
|
|
} else {
|
2023-08-14 12:12:35 -07:00
|
|
|
this.httpCode =
|
|
|
|
this.findProperty(error, ERROR_STATUS_PROPERTIES, ERROR_NESTING_PROPERTIES) ?? null;
|
2023-05-03 00:15:33 -07:00
|
|
|
}
|
|
|
|
|
2023-08-14 12:12:35 -07:00
|
|
|
// set description of this error
|
|
|
|
if (description) {
|
|
|
|
this.description = description;
|
|
|
|
}
|
2021-04-16 09:33:36 -07:00
|
|
|
|
2023-08-14 12:12:35 -07:00
|
|
|
if (!this.description) {
|
|
|
|
if (parseXml) {
|
|
|
|
this.setDescriptionFromXml(error.error as string);
|
|
|
|
} else {
|
|
|
|
this.description = this.findProperty(
|
|
|
|
error,
|
|
|
|
ERROR_MESSAGE_PROPERTIES,
|
|
|
|
ERROR_NESTING_PROPERTIES,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// set message if provided or set default message based on http code
|
|
|
|
if (message) {
|
|
|
|
this.message = message;
|
|
|
|
} else {
|
|
|
|
this.setDefaultStatusCodeMessage();
|
|
|
|
}
|
|
|
|
|
|
|
|
// if message and description are the same, unset redundant description
|
|
|
|
if (this.message === this.description) {
|
|
|
|
this.description = undefined;
|
2021-04-16 09:33:36 -07:00
|
|
|
}
|
|
|
|
|
2023-08-14 12:12:35 -07:00
|
|
|
// if message contain common error code set descriptive message and update description
|
|
|
|
[this.message, this.description] = this.setDescriptiveErrorMessage(
|
|
|
|
this.message,
|
|
|
|
this.description,
|
|
|
|
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
|
|
|
this.httpCode ||
|
|
|
|
(error?.code as string) ||
|
|
|
|
((error?.reason as JsonObject)?.code as string) ||
|
|
|
|
undefined,
|
|
|
|
messageMapping,
|
|
|
|
);
|
2022-06-03 08:25:07 -07:00
|
|
|
|
|
|
|
if (runIndex !== undefined) this.context.runIndex = runIndex;
|
|
|
|
if (itemIndex !== undefined) this.context.itemIndex = itemIndex;
|
2021-04-16 09:33:36 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
private setDescriptionFromXml(xml: string) {
|
|
|
|
parseString(xml, { explicitArray: false }, (_, result) => {
|
|
|
|
if (!result) return;
|
|
|
|
|
2022-07-24 08:25:01 -07:00
|
|
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
2021-04-16 09:33:36 -07:00
|
|
|
const topLevelKey = Object.keys(result)[0];
|
|
|
|
this.description = this.findProperty(
|
2023-08-14 12:12:35 -07:00
|
|
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-member-access
|
2021-04-16 09:33:36 -07:00
|
|
|
result[topLevelKey],
|
|
|
|
ERROR_MESSAGE_PROPERTIES,
|
|
|
|
['Error'].concat(ERROR_NESTING_PROPERTIES),
|
|
|
|
);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set the error's message based on the HTTP status code.
|
|
|
|
*/
|
2023-08-14 12:12:35 -07:00
|
|
|
private setDefaultStatusCodeMessage() {
|
|
|
|
// Set generic error message for 502 Bad Gateway
|
|
|
|
if (!this.httpCode && this.message && this.message.toLowerCase().includes('bad gateway')) {
|
|
|
|
this.httpCode = '502';
|
|
|
|
}
|
|
|
|
|
2021-04-16 09:33:36 -07:00
|
|
|
if (!this.httpCode) {
|
|
|
|
this.httpCode = null;
|
2023-05-03 00:15:33 -07:00
|
|
|
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
|
|
|
this.message = this.message || this.description || UNKNOWN_ERROR_MESSAGE;
|
2021-04-16 09:33:36 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (STATUS_CODE_MESSAGES[this.httpCode]) {
|
2023-08-14 12:12:35 -07:00
|
|
|
this.description = this.updateDescription(this.message, this.description);
|
2021-04-16 09:33:36 -07:00
|
|
|
this.message = STATUS_CODE_MESSAGES[this.httpCode];
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (this.httpCode.charAt(0)) {
|
|
|
|
case '4':
|
2023-08-14 12:12:35 -07:00
|
|
|
this.description = this.updateDescription(this.message, this.description);
|
2021-04-16 09:33:36 -07:00
|
|
|
this.message = STATUS_CODE_MESSAGES['4XX'];
|
|
|
|
break;
|
|
|
|
case '5':
|
2023-08-14 12:12:35 -07:00
|
|
|
this.description = this.updateDescription(this.message, this.description);
|
2021-04-16 09:33:36 -07:00
|
|
|
this.message = STATUS_CODE_MESSAGES['5XX'];
|
|
|
|
break;
|
|
|
|
default:
|
2023-05-03 00:15:33 -07:00
|
|
|
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
|
|
|
this.message = this.message || this.description || UNKNOWN_ERROR_MESSAGE;
|
2021-04-16 09:33:36 -07:00
|
|
|
}
|
2022-11-11 02:32:43 -08:00
|
|
|
if (this.node.type === 'n8n-nodes-base.noOp' && this.message === UNKNOWN_ERROR_MESSAGE) {
|
|
|
|
this.message = `${UNKNOWN_ERROR_MESSAGE_CRED} - ${this.httpCode}`;
|
|
|
|
}
|
2021-04-16 09:33:36 -07:00
|
|
|
}
|
|
|
|
}
|
2023-06-20 08:54:05 -07:00
|
|
|
|
|
|
|
export class NodeSSLError extends ExecutionBaseError {
|
|
|
|
constructor(cause: Error) {
|
|
|
|
super("SSL Issue: consider using the 'Ignore SSL issues' option", { cause });
|
|
|
|
}
|
|
|
|
}
|