mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
refactor(core): Switch plain errors in core
to ApplicationError
(no-changelog) (#7873)
Ensure all errors in `core` are `ApplicationError` or children of it and contain no variables in the message, to continue normalizing all the errors we report to Sentry Follow-up to: https://github.com/n8n-io/n8n/pull/7857
This commit is contained in:
parent
cd474f1562
commit
b16dd21909
|
@ -13,6 +13,7 @@ import type {
|
|||
WorkflowExecuteMode,
|
||||
} from 'n8n-workflow';
|
||||
import {
|
||||
ApplicationError,
|
||||
LoggerProxy as Logger,
|
||||
toCronExpression,
|
||||
WorkflowActivationError,
|
||||
|
@ -177,7 +178,9 @@ export class ActiveWorkflows {
|
|||
for (const cronTime of cronTimes) {
|
||||
const cronTimeParts = cronTime.split(' ');
|
||||
if (cronTimeParts.length > 0 && cronTimeParts[0].includes('*')) {
|
||||
throw new Error('The polling interval is too short. It has to be at least a minute!');
|
||||
throw new ApplicationError(
|
||||
'The polling interval is too short. It has to be at least a minute!',
|
||||
);
|
||||
}
|
||||
|
||||
cronJobs.push(new CronJob(cronTime, executeTrigger, undefined, true, timezone));
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { Container } from 'typedi';
|
||||
import type { ICredentialDataDecryptedObject, ICredentialsEncrypted } from 'n8n-workflow';
|
||||
import { ICredentials, jsonParse } from 'n8n-workflow';
|
||||
import { ApplicationError, ICredentials, jsonParse } from 'n8n-workflow';
|
||||
import { Cipher } from './Cipher';
|
||||
|
||||
export class Credentials extends ICredentials {
|
||||
|
@ -31,13 +31,14 @@ export class Credentials extends ICredentials {
|
|||
*/
|
||||
getData(nodeType?: string): ICredentialDataDecryptedObject {
|
||||
if (nodeType && !this.hasNodeAccess(nodeType)) {
|
||||
throw new Error(
|
||||
`The node of type "${nodeType}" does not have access to credentials "${this.name}" of type "${this.type}".`,
|
||||
);
|
||||
throw new ApplicationError('Node does not have access to credential', {
|
||||
tags: { nodeType, credentialType: this.type },
|
||||
extra: { credentialName: this.name },
|
||||
});
|
||||
}
|
||||
|
||||
if (this.data === undefined) {
|
||||
throw new Error('No data is set so nothing can be returned.');
|
||||
throw new ApplicationError('No data is set so nothing can be returned.');
|
||||
}
|
||||
|
||||
const decryptedData = this.cipher.decrypt(this.data);
|
||||
|
@ -45,7 +46,7 @@ export class Credentials extends ICredentials {
|
|||
try {
|
||||
return jsonParse(decryptedData);
|
||||
} catch (e) {
|
||||
throw new Error(
|
||||
throw new ApplicationError(
|
||||
'Credentials could not be decrypted. The likely reason is that a different "encryptionKey" was used to encrypt the data.',
|
||||
);
|
||||
}
|
||||
|
@ -56,7 +57,7 @@ export class Credentials extends ICredentials {
|
|||
*/
|
||||
getDataToSave(): ICredentialsEncrypted {
|
||||
if (this.data === undefined) {
|
||||
throw new Error('No credentials were set to save.');
|
||||
throw new ApplicationError('No credentials were set to save.');
|
||||
}
|
||||
|
||||
return {
|
||||
|
|
|
@ -14,6 +14,7 @@ import type {
|
|||
KnownNodesAndCredentials,
|
||||
} from 'n8n-workflow';
|
||||
import {
|
||||
ApplicationError,
|
||||
LoggerProxy as Logger,
|
||||
getCredentialsForNode,
|
||||
getVersionedNodeTypeAll,
|
||||
|
@ -116,8 +117,9 @@ export abstract class DirectoryLoader {
|
|||
nodeVersion = tempNode.currentVersion;
|
||||
|
||||
if (currentVersionNode.hasOwnProperty('executeSingle')) {
|
||||
throw new Error(
|
||||
`"executeSingle" has been removed. Please update the code of node "${this.packageName}.${nodeName}" to use "execute" instead!`,
|
||||
throw new ApplicationError(
|
||||
'"executeSingle" has been removed. Please update the code of this node to use "execute" instead!',
|
||||
{ extra: { nodeName: `${this.packageName}.${nodeName}` } },
|
||||
);
|
||||
}
|
||||
} else {
|
||||
|
@ -156,10 +158,10 @@ export abstract class DirectoryLoader {
|
|||
}
|
||||
}
|
||||
|
||||
protected loadCredentialFromFile(credentialName: string, filePath: string): void {
|
||||
protected loadCredentialFromFile(credentialClassName: string, filePath: string): void {
|
||||
let tempCredential: ICredentialType;
|
||||
try {
|
||||
tempCredential = loadClassInIsolation(filePath, credentialName);
|
||||
tempCredential = loadClassInIsolation(filePath, credentialClassName);
|
||||
|
||||
// Add serializer method "toJSON" to the class so that authenticate method (if defined)
|
||||
// gets mapped to the authenticate attribute before it is sent to the client.
|
||||
|
@ -170,8 +172,9 @@ export abstract class DirectoryLoader {
|
|||
this.fixIconPath(tempCredential, filePath);
|
||||
} catch (e) {
|
||||
if (e instanceof TypeError) {
|
||||
throw new Error(
|
||||
`Class with name "${credentialName}" could not be found. Please check if the class is named correctly!`,
|
||||
throw new ApplicationError(
|
||||
'Class could not be found. Please check if the class is named correctly.',
|
||||
{ extra: { credentialClassName } },
|
||||
);
|
||||
} else {
|
||||
throw e;
|
||||
|
@ -179,7 +182,7 @@ export abstract class DirectoryLoader {
|
|||
}
|
||||
|
||||
this.known.credentials[tempCredential.name] = {
|
||||
className: credentialName,
|
||||
className: credentialClassName,
|
||||
sourcePath: filePath,
|
||||
extends: tempCredential.extends,
|
||||
supportedNodes: this.nodesByCredential[tempCredential.name],
|
||||
|
@ -366,7 +369,7 @@ export class PackageDirectoryLoader extends DirectoryLoader {
|
|||
try {
|
||||
return jsonParse<T>(fileString);
|
||||
} catch (error) {
|
||||
throw new Error(`Failed to parse JSON from ${filePath}`);
|
||||
throw new ApplicationError('Failed to parse JSON', { extra: { filePath } });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,13 @@ import type {
|
|||
INodeType,
|
||||
NodeParameterValueType,
|
||||
} from 'n8n-workflow';
|
||||
import { NodeOperationError, NodeHelpers, LoggerProxy, WorkflowOperationError } from 'n8n-workflow';
|
||||
import {
|
||||
NodeOperationError,
|
||||
NodeHelpers,
|
||||
LoggerProxy,
|
||||
WorkflowOperationError,
|
||||
ApplicationError,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
function findPropertyFromParameterName(
|
||||
parameterName: string,
|
||||
|
@ -41,14 +47,14 @@ function findPropertyFromParameterName(
|
|||
property = findProp(param, property.values);
|
||||
currentParamPath += `.${param}`;
|
||||
} else {
|
||||
throw new Error(`Couldn't not find property "${parameterName}"`);
|
||||
throw new ApplicationError('Could not find property', { extra: { parameterName } });
|
||||
}
|
||||
if (!property) {
|
||||
throw new Error(`Couldn't not find property "${parameterName}"`);
|
||||
throw new ApplicationError('Could not find property', { extra: { parameterName } });
|
||||
}
|
||||
}
|
||||
if (!property) {
|
||||
throw new Error(`Couldn't not find property "${parameterName}"`);
|
||||
throw new ApplicationError('Could not find property', { extra: { parameterName } });
|
||||
}
|
||||
|
||||
return property;
|
||||
|
@ -101,17 +107,16 @@ function extractValueRLC(
|
|||
LoggerProxy.error(
|
||||
`Only strings can be passed to extractValue. Parameter "${parameterName}" passed "${typeName}"`,
|
||||
);
|
||||
throw new Error(
|
||||
`ERROR: ${property.displayName} parameter's value is invalid. Please enter a valid ${modeProp.displayName}.`,
|
||||
throw new ApplicationError(
|
||||
"ERROR: This parameter's value is invalid. Please enter a valid mode.",
|
||||
{ extra: { parameter: property.displayName, modeProp: modeProp.displayName } },
|
||||
);
|
||||
}
|
||||
|
||||
if (modeProp.extractValue.type !== 'regex') {
|
||||
throw new Error(
|
||||
`Property "${parameterName}" has an unknown extractValue type "${
|
||||
modeProp.extractValue.type as string
|
||||
}"`,
|
||||
);
|
||||
throw new ApplicationError('Property with unknown `extractValue`', {
|
||||
extra: { parameter: parameterName, extractValueType: modeProp.extractValue.type },
|
||||
});
|
||||
}
|
||||
|
||||
const regex = new RegExp(modeProp.extractValue.regex);
|
||||
|
@ -137,17 +142,15 @@ function extractValueOther(
|
|||
LoggerProxy.error(
|
||||
`Only strings can be passed to extractValue. Parameter "${parameterName}" passed "${typeName}"`,
|
||||
);
|
||||
throw new Error(
|
||||
`ERROR: ${property.displayName} parameter's value is invalid. Please enter a valid value.`,
|
||||
);
|
||||
throw new ApplicationError("This parameter's value is invalid", {
|
||||
extra: { parameter: property.displayName },
|
||||
});
|
||||
}
|
||||
|
||||
if (property.extractValue.type !== 'regex') {
|
||||
throw new Error(
|
||||
`Property "${parameterName}" has an unknown extractValue type "${
|
||||
property.extractValue.type as string
|
||||
}"`,
|
||||
);
|
||||
throw new ApplicationError('Property with unknown `extractValue`', {
|
||||
extra: { parameter: parameterName, extractValueType: property.extractValue.type },
|
||||
});
|
||||
}
|
||||
|
||||
const regex = new RegExp(property.extractValue.regex);
|
||||
|
|
|
@ -112,6 +112,7 @@ import {
|
|||
validateFieldType,
|
||||
ExecutionBaseError,
|
||||
jsonParse,
|
||||
ApplicationError,
|
||||
} from 'n8n-workflow';
|
||||
import type { Token } from 'oauth-1.0a';
|
||||
import clientOAuth1 from 'oauth-1.0a';
|
||||
|
@ -1198,7 +1199,7 @@ export async function requestOAuth2(
|
|||
credentials.grantType === OAuth2GrantType.authorizationCode &&
|
||||
credentials.oauthTokenData === undefined
|
||||
) {
|
||||
throw new Error('OAuth credentials not connected!');
|
||||
throw new ApplicationError('OAuth credentials not connected');
|
||||
}
|
||||
|
||||
const oAuthClient = new ClientOAuth2({
|
||||
|
@ -1218,9 +1219,10 @@ export async function requestOAuth2(
|
|||
const { data } = await getClientCredentialsToken(oAuthClient, credentials);
|
||||
// Find the credentials
|
||||
if (!node.credentials?.[credentialsType]) {
|
||||
throw new Error(
|
||||
`The node "${node.name}" does not have credentials of type "${credentialsType}"!`,
|
||||
);
|
||||
throw new ApplicationError('Node does not have credential type', {
|
||||
extra: { nodeName: node.name },
|
||||
tags: { credentialType: credentialsType },
|
||||
});
|
||||
}
|
||||
|
||||
const nodeCredentials = node.credentials[credentialsType];
|
||||
|
@ -1302,9 +1304,9 @@ export async function requestOAuth2(
|
|||
credentials.oauthTokenData = newToken.data;
|
||||
// Find the credentials
|
||||
if (!node.credentials?.[credentialsType]) {
|
||||
throw new Error(
|
||||
`The node "${node.name}" does not have credentials of type "${credentialsType}"!`,
|
||||
);
|
||||
throw new ApplicationError('Node does not have credential type', {
|
||||
extra: { nodeName: node.name, credentialType: credentialsType },
|
||||
});
|
||||
}
|
||||
const nodeCredentials = node.credentials[credentialsType];
|
||||
await additionalData.credentialsHelper.updateCredentials(
|
||||
|
@ -1379,9 +1381,10 @@ export async function requestOAuth2(
|
|||
|
||||
// Find the credentials
|
||||
if (!node.credentials?.[credentialsType]) {
|
||||
throw new Error(
|
||||
`The node "${node.name}" does not have credentials of type "${credentialsType}"!`,
|
||||
);
|
||||
throw new ApplicationError('Node does not have credential type', {
|
||||
tags: { credentialType: credentialsType },
|
||||
extra: { nodeName: node.name },
|
||||
});
|
||||
}
|
||||
const nodeCredentials = node.credentials[credentialsType];
|
||||
|
||||
|
@ -1426,11 +1429,11 @@ export async function requestOAuth1(
|
|||
const credentials = await this.getCredentials(credentialsType);
|
||||
|
||||
if (credentials === undefined) {
|
||||
throw new Error('No credentials were returned!');
|
||||
throw new ApplicationError('No credentials were returned!');
|
||||
}
|
||||
|
||||
if (credentials.oauthTokenData === undefined) {
|
||||
throw new Error('OAuth credentials not connected!');
|
||||
throw new ApplicationError('OAuth credentials not connected!');
|
||||
}
|
||||
|
||||
const oauth = new clientOAuth1({
|
||||
|
@ -1651,7 +1654,7 @@ export function normalizeItems(
|
|||
return executionData;
|
||||
|
||||
if (executionData.some((item) => typeof item === 'object' && 'json' in item)) {
|
||||
throw new Error('Inconsistent item format');
|
||||
throw new ApplicationError('Inconsistent item format');
|
||||
}
|
||||
|
||||
if (executionData.every((item) => typeof item === 'object' && 'binary' in item)) {
|
||||
|
@ -1671,7 +1674,7 @@ export function normalizeItems(
|
|||
}
|
||||
|
||||
if (executionData.some((item) => typeof item === 'object' && 'binary' in item)) {
|
||||
throw new Error('Inconsistent item format');
|
||||
throw new ApplicationError('Inconsistent item format');
|
||||
}
|
||||
|
||||
return executionData.map((item) => {
|
||||
|
@ -2229,13 +2232,15 @@ export function getNodeParameter(
|
|||
): NodeParameterValueType | object {
|
||||
const nodeType = workflow.nodeTypes.getByNameAndVersion(node.type, node.typeVersion);
|
||||
if (nodeType === undefined) {
|
||||
throw new Error(`Node type "${node.type}" is not known so can not return parameter value!`);
|
||||
throw new ApplicationError('Node type is unknown so cannot return parameter value', {
|
||||
tags: { nodeType: node.type },
|
||||
});
|
||||
}
|
||||
|
||||
const value = get(node.parameters, parameterName, fallbackValue);
|
||||
|
||||
if (value === undefined) {
|
||||
throw new Error(`Could not get parameter "${parameterName}"!`);
|
||||
throw new ApplicationError('Could not get parameter', { extra: { parameterName } });
|
||||
}
|
||||
|
||||
if (options?.rawExpressions) {
|
||||
|
@ -2393,7 +2398,9 @@ const addExecutionDataFunctions = async (
|
|||
currentNodeRunIndex: number,
|
||||
): Promise<void> => {
|
||||
if (connectionType === 'main') {
|
||||
throw new Error(`Setting the ${type} is not supported for the main connection!`);
|
||||
throw new ApplicationError('Setting type is not supported for main connection', {
|
||||
extra: { type },
|
||||
});
|
||||
}
|
||||
|
||||
let taskData: ITaskData | undefined;
|
||||
|
@ -2946,7 +2953,7 @@ const getBinaryHelperFunctions = (
|
|||
setBinaryDataBuffer: async (data, binaryData) =>
|
||||
setBinaryDataBuffer(data, binaryData, workflowId, executionId!),
|
||||
copyBinaryFile: async () => {
|
||||
throw new Error('copyBinaryFile has been removed. Please upgrade this node');
|
||||
throw new ApplicationError('`copyBinaryFile` has been removed. Please upgrade this node.');
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -2983,10 +2990,12 @@ export function getExecutePollFunctions(
|
|||
return {
|
||||
...getCommonWorkflowFunctions(workflow, node, additionalData),
|
||||
__emit: (data: INodeExecutionData[][]): void => {
|
||||
throw new Error('Overwrite NodeExecuteFunctions.getExecutePollFunctions.__emit function!');
|
||||
throw new ApplicationError(
|
||||
'Overwrite NodeExecuteFunctions.getExecutePollFunctions.__emit function!',
|
||||
);
|
||||
},
|
||||
__emitError(error: Error) {
|
||||
throw new Error(
|
||||
throw new ApplicationError(
|
||||
'Overwrite NodeExecuteFunctions.getExecutePollFunctions.__emitError function!',
|
||||
);
|
||||
},
|
||||
|
@ -3043,10 +3052,14 @@ export function getExecuteTriggerFunctions(
|
|||
return {
|
||||
...getCommonWorkflowFunctions(workflow, node, additionalData),
|
||||
emit: (data: INodeExecutionData[][]): void => {
|
||||
throw new Error('Overwrite NodeExecuteFunctions.getExecuteTriggerFunctions.emit function!');
|
||||
throw new ApplicationError(
|
||||
'Overwrite NodeExecuteFunctions.getExecuteTriggerFunctions.emit function!',
|
||||
);
|
||||
},
|
||||
emitError: (error: Error): void => {
|
||||
throw new Error('Overwrite NodeExecuteFunctions.getExecuteTriggerFunctions.emit function!');
|
||||
throw new ApplicationError(
|
||||
'Overwrite NodeExecuteFunctions.getExecuteTriggerFunctions.emit function!',
|
||||
);
|
||||
},
|
||||
getMode: () => mode,
|
||||
getActivationMode: () => activation,
|
||||
|
@ -3174,7 +3187,9 @@ export function getExecuteFunctions(
|
|||
});
|
||||
|
||||
if (inputConfiguration === undefined) {
|
||||
throw new Error(`The node "${node.name}" does not have an input of type "${inputName}"`);
|
||||
throw new ApplicationError('Node does not have input of type', {
|
||||
extra: { nodeName: node.name, inputName },
|
||||
});
|
||||
}
|
||||
|
||||
if (typeof inputConfiguration === 'string') {
|
||||
|
@ -3200,9 +3215,9 @@ export function getExecuteFunctions(
|
|||
);
|
||||
|
||||
if (!nodeType.supplyData) {
|
||||
throw new Error(
|
||||
`The node "${connectedNode.name}" does not have a "supplyData" method defined!`,
|
||||
);
|
||||
throw new ApplicationError('Node does not have a `supplyData` method defined', {
|
||||
extra: { nodeName: connectedNode.name },
|
||||
});
|
||||
}
|
||||
|
||||
const context = Object.assign({}, this);
|
||||
|
@ -3350,12 +3365,15 @@ export function getExecuteFunctions(
|
|||
|
||||
// TODO: Check if nodeType has input with that index defined
|
||||
if (inputData[inputName].length < inputIndex) {
|
||||
throw new Error(`Could not get input index "${inputIndex}" of input "${inputName}"!`);
|
||||
throw new ApplicationError('Could not get input with given index', {
|
||||
extra: { inputIndex, inputName },
|
||||
});
|
||||
}
|
||||
|
||||
if (inputData[inputName][inputIndex] === null) {
|
||||
// return [];
|
||||
throw new Error(`Value "${inputIndex}" of input "${inputName}" did not get set!`);
|
||||
throw new ApplicationError('Value of input was not set', {
|
||||
extra: { inputIndex, inputName },
|
||||
});
|
||||
}
|
||||
|
||||
return inputData[inputName][inputIndex] as INodeExecutionData[];
|
||||
|
@ -3363,7 +3381,7 @@ export function getExecuteFunctions(
|
|||
getInputSourceData: (inputIndex = 0, inputName = 'main') => {
|
||||
if (executeData?.source === null) {
|
||||
// Should never happen as n8n sets it automatically
|
||||
throw new Error('Source data is missing!');
|
||||
throw new ApplicationError('Source data is missing');
|
||||
}
|
||||
return executeData.source[inputName][inputIndex];
|
||||
},
|
||||
|
@ -3573,21 +3591,23 @@ export function getExecuteSingleFunctions(
|
|||
|
||||
// TODO: Check if nodeType has input with that index defined
|
||||
if (inputData[inputName].length < inputIndex) {
|
||||
throw new Error(`Could not get input index "${inputIndex}" of input "${inputName}"!`);
|
||||
throw new ApplicationError('Could not get input index', {
|
||||
extra: { inputIndex, inputName },
|
||||
});
|
||||
}
|
||||
|
||||
const allItems = inputData[inputName][inputIndex];
|
||||
|
||||
if (allItems === null) {
|
||||
// return [];
|
||||
throw new Error(`Value "${inputIndex}" of input "${inputName}" did not get set!`);
|
||||
throw new ApplicationError('Input index was not set', {
|
||||
extra: { inputIndex, inputName },
|
||||
});
|
||||
}
|
||||
|
||||
if (allItems[itemIndex] === null) {
|
||||
// return [];
|
||||
throw new Error(
|
||||
`Value "${inputIndex}" of input "${inputName}" with itemIndex "${itemIndex}" did not get set!`,
|
||||
);
|
||||
throw new ApplicationError('Value of input with given index was not set', {
|
||||
extra: { inputIndex, inputName, itemIndex },
|
||||
});
|
||||
}
|
||||
|
||||
return allItems[itemIndex];
|
||||
|
@ -3595,7 +3615,7 @@ export function getExecuteSingleFunctions(
|
|||
getInputSourceData: (inputIndex = 0, inputName = 'main') => {
|
||||
if (executeData?.source === null) {
|
||||
// Should never happen as n8n sets it automatically
|
||||
throw new Error('Source data is missing!');
|
||||
throw new ApplicationError('Source data is missing');
|
||||
}
|
||||
return executeData.source[inputName][inputIndex] as ISourceData;
|
||||
},
|
||||
|
@ -3691,9 +3711,9 @@ export function getLoadOptionsFunctions(
|
|||
if (options?.extractValue) {
|
||||
const nodeType = workflow.nodeTypes.getByNameAndVersion(node.type, node.typeVersion);
|
||||
if (nodeType === undefined) {
|
||||
throw new Error(
|
||||
`Node type "${node.type}" is not known so can not return parameter value!`,
|
||||
);
|
||||
throw new ApplicationError('Node type is not known so cannot return parameter value', {
|
||||
tags: { nodeType: node.type },
|
||||
});
|
||||
}
|
||||
returnData = extractValue(
|
||||
returnData,
|
||||
|
@ -3793,7 +3813,7 @@ export function getExecuteHookFunctions(
|
|||
},
|
||||
getWebhookName(): string {
|
||||
if (webhookData === undefined) {
|
||||
throw new Error('Is only supported in webhook functions!');
|
||||
throw new ApplicationError('Only supported in webhook functions');
|
||||
}
|
||||
return webhookData.webhookDescription.name;
|
||||
},
|
||||
|
@ -3818,14 +3838,14 @@ export function getExecuteWebhookFunctions(
|
|||
...getCommonWorkflowFunctions(workflow, node, additionalData),
|
||||
getBodyData(): IDataObject {
|
||||
if (additionalData.httpRequest === undefined) {
|
||||
throw new Error('Request is missing!');
|
||||
throw new ApplicationError('Request is missing');
|
||||
}
|
||||
return additionalData.httpRequest.body;
|
||||
},
|
||||
getCredentials: async (type) => getCredentials(workflow, node, type, additionalData, mode),
|
||||
getHeaderData(): IncomingHttpHeaders {
|
||||
if (additionalData.httpRequest === undefined) {
|
||||
throw new Error('Request is missing!');
|
||||
throw new ApplicationError('Request is missing');
|
||||
}
|
||||
return additionalData.httpRequest.headers;
|
||||
},
|
||||
|
@ -3857,25 +3877,25 @@ export function getExecuteWebhookFunctions(
|
|||
},
|
||||
getParamsData(): object {
|
||||
if (additionalData.httpRequest === undefined) {
|
||||
throw new Error('Request is missing!');
|
||||
throw new ApplicationError('Request is missing');
|
||||
}
|
||||
return additionalData.httpRequest.params;
|
||||
},
|
||||
getQueryData(): object {
|
||||
if (additionalData.httpRequest === undefined) {
|
||||
throw new Error('Request is missing!');
|
||||
throw new ApplicationError('Request is missing');
|
||||
}
|
||||
return additionalData.httpRequest.query;
|
||||
},
|
||||
getRequestObject(): Request {
|
||||
if (additionalData.httpRequest === undefined) {
|
||||
throw new Error('Request is missing!');
|
||||
throw new ApplicationError('Request is missing');
|
||||
}
|
||||
return additionalData.httpRequest;
|
||||
},
|
||||
getResponseObject(): Response {
|
||||
if (additionalData.httpResponse === undefined) {
|
||||
throw new Error('Response is missing!');
|
||||
throw new ApplicationError('Response is missing');
|
||||
}
|
||||
return additionalData.httpResponse;
|
||||
},
|
||||
|
|
|
@ -5,7 +5,7 @@ import axios from 'axios';
|
|||
import { Service } from 'typedi';
|
||||
import { sign } from 'aws4';
|
||||
import { isStream, parseXml, writeBlockedMessage } from './utils';
|
||||
import { LoggerProxy as Logger } from 'n8n-workflow';
|
||||
import { ApplicationError, LoggerProxy as Logger } from 'n8n-workflow';
|
||||
|
||||
import type { AxiosRequestConfig, AxiosResponse, Method } from 'axios';
|
||||
import type { Request as Aws4Options, Credentials as Aws4Credentials } from 'aws4';
|
||||
|
@ -283,7 +283,7 @@ export class ObjectStoreService {
|
|||
|
||||
this.logger.error(message, { config });
|
||||
|
||||
throw new Error(message, { cause: { error, details: config } });
|
||||
throw new ApplicationError(message, { cause: error, extra: { config } });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@ import {
|
|||
WorkflowOperationError,
|
||||
NodeHelpers,
|
||||
NodeConnectionType,
|
||||
ApplicationError,
|
||||
} from 'n8n-workflow';
|
||||
import get from 'lodash/get';
|
||||
import * as NodeExecuteFunctions from './NodeExecuteFunctions';
|
||||
|
@ -89,7 +90,7 @@ export class WorkflowExecute {
|
|||
startNode = startNode || workflow.getStartNode(destinationNode);
|
||||
|
||||
if (startNode === undefined) {
|
||||
throw new Error('No node to start the workflow from could be found!');
|
||||
throw new ApplicationError('No node to start the workflow from could be found');
|
||||
}
|
||||
|
||||
// If a destination node is given we only run the direct parent nodes and no others
|
||||
|
@ -929,7 +930,9 @@ export class WorkflowExecute {
|
|||
currentExecutionTry = `${executionNode.name}:${runIndex}`;
|
||||
|
||||
if (currentExecutionTry === lastExecutionTry) {
|
||||
throw new Error('Did stop execution because execution seems to be in endless loop.');
|
||||
throw new ApplicationError(
|
||||
'Stopped execution because it seems to be in an endless loop',
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
|
@ -1412,9 +1415,12 @@ export class WorkflowExecute {
|
|||
outputIndex
|
||||
]) {
|
||||
if (!workflow.nodes.hasOwnProperty(connectionData.node)) {
|
||||
throw new Error(
|
||||
`The node "${executionNode.name}" connects to not found node "${connectionData.node}"`,
|
||||
);
|
||||
throw new ApplicationError('Destination node not found', {
|
||||
extra: {
|
||||
sourceNodeName: executionNode.name,
|
||||
destinationNodeName: connectionData.node,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (
|
||||
|
|
|
@ -84,9 +84,7 @@ describe('Credentials', () => {
|
|||
credentials.getData('base.otherNode');
|
||||
expect(true).toBe(false);
|
||||
} catch (e) {
|
||||
expect(e.message).toBe(
|
||||
'The node of type "base.otherNode" does not have access to credentials "testName" of type "testType".',
|
||||
);
|
||||
expect(e.message).toBe('Node does not have access to credential');
|
||||
}
|
||||
|
||||
// Get the data which will be saved in database
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import type { IRun, WorkflowTestData } from 'n8n-workflow';
|
||||
import { createDeferredPromise, Workflow } from 'n8n-workflow';
|
||||
import { ApplicationError, createDeferredPromise, Workflow } from 'n8n-workflow';
|
||||
import { WorkflowExecute } from '@/WorkflowExecute';
|
||||
|
||||
import * as Helpers from './helpers';
|
||||
|
@ -45,7 +45,7 @@ describe('WorkflowExecute', () => {
|
|||
// Check if the output data of the nodes is correct
|
||||
for (const nodeName of Object.keys(testData.output.nodeData)) {
|
||||
if (result.data.resultData.runData[nodeName] === undefined) {
|
||||
throw new Error(`Data for node "${nodeName}" is missing!`);
|
||||
throw new ApplicationError('Data for node is missing', { extra: { nodeName } });
|
||||
}
|
||||
|
||||
const resultData = result.data.resultData.runData[nodeName].map((nodeData) => {
|
||||
|
@ -108,7 +108,7 @@ describe('WorkflowExecute', () => {
|
|||
// Check if the output data of the nodes is correct
|
||||
for (const nodeName of Object.keys(testData.output.nodeData)) {
|
||||
if (result.data.resultData.runData[nodeName] === undefined) {
|
||||
throw new Error(`Data for node "${nodeName}" is missing!`);
|
||||
throw new ApplicationError('Data for node is missing', { extra: { nodeName } });
|
||||
}
|
||||
|
||||
const resultData = result.data.resultData.runData[nodeName].map((nodeData) => {
|
||||
|
@ -172,7 +172,7 @@ describe('WorkflowExecute', () => {
|
|||
// Check if the output data of the nodes is correct
|
||||
for (const nodeName of Object.keys(testData.output.nodeData)) {
|
||||
if (result.data.resultData.runData[nodeName] === undefined) {
|
||||
throw new Error(`Data for node "${nodeName}" is missing!`);
|
||||
throw new ApplicationError('Data for node is missing', { extra: { nodeName } });
|
||||
}
|
||||
|
||||
const resultData = result.data.resultData.runData[nodeName].map((nodeData) => {
|
||||
|
|
|
@ -24,7 +24,7 @@ import type {
|
|||
INodeTypeData,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import { ICredentialsHelper, NodeHelpers, WorkflowHooks } from 'n8n-workflow';
|
||||
import { ApplicationError, ICredentialsHelper, NodeHelpers, WorkflowHooks } from 'n8n-workflow';
|
||||
import { Credentials } from '@/Credentials';
|
||||
|
||||
import { predefinedNodesTypes } from './constants';
|
||||
|
@ -177,11 +177,11 @@ export function getNodeTypes(testData: WorkflowTestData[] | WorkflowTestData) {
|
|||
|
||||
for (const nodeName of nodeNames) {
|
||||
if (!nodeName.startsWith('n8n-nodes-base.')) {
|
||||
throw new Error(`Unknown node type: ${nodeName}`);
|
||||
throw new ApplicationError('Unknown node type', { tags: { nodeType: nodeName } });
|
||||
}
|
||||
const loadInfo = knownNodes[nodeName.replace('n8n-nodes-base.', '')];
|
||||
if (!loadInfo) {
|
||||
throw new Error(`Unknown node type: ${nodeName}`);
|
||||
throw new ApplicationError('Unknown node type', { tags: { nodeType: nodeName } });
|
||||
}
|
||||
const sourcePath = loadInfo.sourcePath.replace(/^dist\//, './').replace(/\.js$/, '.ts');
|
||||
const nodeSourcePath = path.join(BASE_DIR, 'nodes-base', sourcePath);
|
||||
|
@ -218,7 +218,7 @@ export const workflowToTests = (dirname: string, testFolder = 'workflows') => {
|
|||
const description = filePath.replace('.json', '');
|
||||
const workflowData = readJsonFileSync<IWorkflowBase>(filePath);
|
||||
if (workflowData.pinData === undefined) {
|
||||
throw new Error('Workflow data does not contain pinData');
|
||||
throw new ApplicationError('Workflow data does not contain pinData');
|
||||
}
|
||||
|
||||
const nodeData = preparePinData(workflowData.pinData);
|
||||
|
|
Loading…
Reference in a new issue