mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
refactor(core): Migrate all errors in cli package to new hierarchy (#13478)
Co-authored-by: Tomi Turtiainen <10324676+tomi@users.noreply.github.com>
This commit is contained in:
parent
719e3c2cf7
commit
3ca99194c6
|
@ -2,7 +2,7 @@ import type { GlobalConfig } from '@n8n/config';
|
|||
import { mock } from 'jest-mock-extended';
|
||||
import type { ErrorReporter, Logger } from 'n8n-core';
|
||||
import type { IWorkflowBase } from 'n8n-workflow';
|
||||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { UnexpectedError } from 'n8n-workflow';
|
||||
|
||||
import type { CredentialsRepository } from '@/databases/repositories/credentials.repository';
|
||||
import type { SettingsRepository } from '@/databases/repositories/settings.repository';
|
||||
|
@ -57,7 +57,7 @@ describe('ExternalHooks', () => {
|
|||
{ virtual: true },
|
||||
);
|
||||
|
||||
await expect(externalHooks.init()).rejects.toThrow(ApplicationError);
|
||||
await expect(externalHooks.init()).rejects.toThrow(UnexpectedError);
|
||||
});
|
||||
|
||||
it('should successfully load hooks from valid hook file', async () => {
|
||||
|
@ -112,10 +112,13 @@ describe('ExternalHooks', () => {
|
|||
externalHooks['registered']['workflow.create'] = [hookFn];
|
||||
|
||||
await expect(externalHooks.run('workflow.create', [workflowData])).rejects.toThrow(error);
|
||||
|
||||
expect(errorReporter.error).toHaveBeenCalledWith(expect.any(ApplicationError), {
|
||||
level: 'fatal',
|
||||
});
|
||||
expect(errorReporter.error).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
message: 'External hook "workflow.create" failed',
|
||||
cause: error,
|
||||
}),
|
||||
{ level: 'fatal' },
|
||||
);
|
||||
expect(logger.error).toHaveBeenCalledWith(
|
||||
'There was a problem running hook "workflow.create"',
|
||||
);
|
||||
|
|
|
@ -30,7 +30,7 @@ import {
|
|||
Workflow,
|
||||
WorkflowActivationError,
|
||||
WebhookPathTakenError,
|
||||
ApplicationError,
|
||||
UnexpectedError,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import { ActivationErrorsService } from '@/activation-errors.service';
|
||||
|
@ -238,7 +238,7 @@ export class ActiveWorkflowManager {
|
|||
});
|
||||
|
||||
if (workflowData === null) {
|
||||
throw new ApplicationError('Could not find workflow', { extra: { workflowId } });
|
||||
throw new UnexpectedError('Could not find workflow', { extra: { workflowId } });
|
||||
}
|
||||
|
||||
const workflow = new Workflow({
|
||||
|
|
|
@ -2,7 +2,7 @@ import type { PushPayload } from '@n8n/api-types';
|
|||
import { Service } from '@n8n/di';
|
||||
import { ErrorReporter } from 'n8n-core';
|
||||
import type { Workflow } from 'n8n-workflow';
|
||||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { UnexpectedError } from 'n8n-workflow';
|
||||
|
||||
import { CollaborationState } from '@/collaboration/collaboration.state';
|
||||
import type { User } from '@/databases/entities/user';
|
||||
|
@ -34,7 +34,7 @@ export class CollaborationService {
|
|||
await this.handleUserMessage(event.userId, event.msg);
|
||||
} catch (error) {
|
||||
this.errorReporter.error(
|
||||
new ApplicationError('Error handling CollaborationService push message', {
|
||||
new UnexpectedError('Error handling CollaborationService push message', {
|
||||
extra: {
|
||||
msg: event.msg,
|
||||
userId: event.userId,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { SecurityConfig } from '@n8n/config';
|
||||
import { Container } from '@n8n/di';
|
||||
import { Flags } from '@oclif/core';
|
||||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { UserError } from 'n8n-workflow';
|
||||
|
||||
import { RISK_CATEGORIES } from '@/security-audit/constants';
|
||||
import { SecurityAuditService } from '@/security-audit/security-audit.service';
|
||||
|
@ -48,7 +48,7 @@ export class SecurityAudit extends BaseCommand {
|
|||
|
||||
const hint = `Valid categories are: ${RISK_CATEGORIES.join(', ')}`;
|
||||
|
||||
throw new ApplicationError([message, hint].join('. '));
|
||||
throw new UserError([message, hint].join('. '));
|
||||
}
|
||||
|
||||
const result = await Container.get(SecurityAuditService).run(
|
||||
|
|
|
@ -10,7 +10,7 @@ import {
|
|||
DataDeduplicationService,
|
||||
ErrorReporter,
|
||||
} from 'n8n-core';
|
||||
import { ApplicationError, ensureError, sleep } from 'n8n-workflow';
|
||||
import { ensureError, sleep, UserError } from 'n8n-workflow';
|
||||
|
||||
import type { AbstractServer } from '@/abstract-server';
|
||||
import config from '@/config';
|
||||
|
@ -151,7 +151,7 @@ export abstract class BaseCommand extends Command {
|
|||
if (!isSelected && !isAvailable) return;
|
||||
|
||||
if (isSelected && !isAvailable) {
|
||||
throw new ApplicationError(
|
||||
throw new UserError(
|
||||
'External storage selected but unavailable. Please make external storage available by adding "s3" to `N8N_AVAILABLE_BINARY_DATA_MODES`.',
|
||||
);
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ import fs from 'fs';
|
|||
import { diff } from 'json-diff';
|
||||
import pick from 'lodash/pick';
|
||||
import type { IRun, ITaskData, IWorkflowBase, IWorkflowExecutionDataProcess } from 'n8n-workflow';
|
||||
import { ApplicationError, jsonParse } from 'n8n-workflow';
|
||||
import { jsonParse, UnexpectedError } from 'n8n-workflow';
|
||||
import os from 'os';
|
||||
import { sep } from 'path';
|
||||
|
||||
|
@ -472,7 +472,7 @@ export class ExecuteBatch extends BaseCommand {
|
|||
this.updateStatus();
|
||||
}
|
||||
} else {
|
||||
throw new ApplicationError('Wrong execution status - cannot proceed');
|
||||
throw new UnexpectedError('Wrong execution status - cannot proceed');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { Container } from '@n8n/di';
|
||||
import { Flags } from '@oclif/core';
|
||||
import type { IWorkflowBase, IWorkflowExecutionDataProcess } from 'n8n-workflow';
|
||||
import { ApplicationError, ExecutionBaseError } from 'n8n-workflow';
|
||||
import { ExecutionBaseError, UnexpectedError, UserError } from 'n8n-workflow';
|
||||
|
||||
import { ActiveExecutions } from '@/active-executions';
|
||||
import { WorkflowRepository } from '@/databases/repositories/workflow.repository';
|
||||
|
@ -44,7 +44,7 @@ export class Execute extends BaseCommand {
|
|||
}
|
||||
|
||||
if (flags.file) {
|
||||
throw new ApplicationError(
|
||||
throw new UserError(
|
||||
'The --file flag is no longer supported. Please first import the workflow and then execute it using the --id flag.',
|
||||
{ level: 'warning' },
|
||||
);
|
||||
|
@ -64,7 +64,7 @@ export class Execute extends BaseCommand {
|
|||
}
|
||||
|
||||
if (!workflowData) {
|
||||
throw new ApplicationError('Failed to retrieve workflow data for requested workflow');
|
||||
throw new UnexpectedError('Failed to retrieve workflow data for requested workflow');
|
||||
}
|
||||
|
||||
if (!isWorkflowIdValid(workflowId)) {
|
||||
|
@ -87,7 +87,7 @@ export class Execute extends BaseCommand {
|
|||
const data = await activeExecutions.getPostExecutePromise(executionId);
|
||||
|
||||
if (data === undefined) {
|
||||
throw new ApplicationError('Workflow did not return any data');
|
||||
throw new UnexpectedError('Workflow did not return any data');
|
||||
}
|
||||
|
||||
if (data.data.resultData.error) {
|
||||
|
|
|
@ -2,7 +2,7 @@ import { Container } from '@n8n/di';
|
|||
import { Flags } from '@oclif/core';
|
||||
import fs from 'fs';
|
||||
import { Credentials } from 'n8n-core';
|
||||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { UserError } from 'n8n-workflow';
|
||||
import path from 'path';
|
||||
|
||||
import { CredentialsRepository } from '@/databases/repositories/credentials.repository';
|
||||
|
@ -123,7 +123,7 @@ export class ExportCredentialsCommand extends BaseCommand {
|
|||
}
|
||||
|
||||
if (credentials.length === 0) {
|
||||
throw new ApplicationError('No credentials found with specified filters');
|
||||
throw new UserError('No credentials found with specified filters');
|
||||
}
|
||||
|
||||
if (flags.separate) {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { Container } from '@n8n/di';
|
||||
import { Flags } from '@oclif/core';
|
||||
import fs from 'fs';
|
||||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { UserError } from 'n8n-workflow';
|
||||
import path from 'path';
|
||||
|
||||
import { WorkflowRepository } from '@/databases/repositories/workflow.repository';
|
||||
|
@ -107,7 +107,7 @@ export class ExportWorkflowsCommand extends BaseCommand {
|
|||
});
|
||||
|
||||
if (workflows.length === 0) {
|
||||
throw new ApplicationError('No workflows found with specified filters');
|
||||
throw new UserError('No workflows found with specified filters');
|
||||
}
|
||||
|
||||
if (flags.separate) {
|
||||
|
|
|
@ -6,7 +6,7 @@ import glob from 'fast-glob';
|
|||
import fs from 'fs';
|
||||
import { Cipher } from 'n8n-core';
|
||||
import type { ICredentialsEncrypted } from 'n8n-workflow';
|
||||
import { ApplicationError, jsonParse } from 'n8n-workflow';
|
||||
import { jsonParse, UserError } from 'n8n-workflow';
|
||||
|
||||
import { UM_FIX_INSTRUCTION } from '@/constants';
|
||||
import { CredentialsEntity } from '@/databases/entities/credentials-entity';
|
||||
|
@ -66,7 +66,7 @@ export class ImportCredentialsCommand extends BaseCommand {
|
|||
}
|
||||
|
||||
if (flags.projectId && flags.userId) {
|
||||
throw new ApplicationError(
|
||||
throw new UserError(
|
||||
'You cannot use `--userId` and `--projectId` together. Use one or the other.',
|
||||
);
|
||||
}
|
||||
|
@ -81,7 +81,7 @@ export class ImportCredentialsCommand extends BaseCommand {
|
|||
const result = await this.checkRelations(credentials, flags.projectId, flags.userId);
|
||||
|
||||
if (!result.success) {
|
||||
throw new ApplicationError(result.message);
|
||||
throw new UserError(result.message);
|
||||
}
|
||||
|
||||
for (const credential of credentials) {
|
||||
|
@ -202,7 +202,7 @@ export class ImportCredentialsCommand extends BaseCommand {
|
|||
);
|
||||
|
||||
if (!Array.isArray(credentialsUnchecked)) {
|
||||
throw new ApplicationError(
|
||||
throw new UserError(
|
||||
'File does not seem to contain credentials. Make sure the credentials are contained in an array.',
|
||||
);
|
||||
}
|
||||
|
@ -252,7 +252,7 @@ export class ImportCredentialsCommand extends BaseCommand {
|
|||
if (!userId) {
|
||||
const owner = await this.transactionManager.findOneBy(User, { role: 'global:owner' });
|
||||
if (!owner) {
|
||||
throw new ApplicationError(`Failed to find owner. ${UM_FIX_INSTRUCTION}`);
|
||||
throw new UserError(`Failed to find owner. ${UM_FIX_INSTRUCTION}`);
|
||||
}
|
||||
userId = owner.id;
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ import { Flags } from '@oclif/core';
|
|||
import glob from 'fast-glob';
|
||||
import fs from 'fs';
|
||||
import type { IWorkflowBase, WorkflowId } from 'n8n-workflow';
|
||||
import { ApplicationError, jsonParse } from 'n8n-workflow';
|
||||
import { jsonParse, UserError } from 'n8n-workflow';
|
||||
|
||||
import { UM_FIX_INSTRUCTION } from '@/constants';
|
||||
import type { WorkflowEntity } from '@/databases/entities/workflow-entity';
|
||||
|
@ -19,7 +19,7 @@ import { BaseCommand } from '../base-command';
|
|||
|
||||
function assertHasWorkflowsToImport(workflows: unknown): asserts workflows is IWorkflowToImport[] {
|
||||
if (!Array.isArray(workflows)) {
|
||||
throw new ApplicationError(
|
||||
throw new UserError(
|
||||
'File does not seem to contain workflows. Make sure the workflows are contained in an array.',
|
||||
);
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ function assertHasWorkflowsToImport(workflows: unknown): asserts workflows is IW
|
|||
!Object.prototype.hasOwnProperty.call(workflow, 'nodes') ||
|
||||
!Object.prototype.hasOwnProperty.call(workflow, 'connections')
|
||||
) {
|
||||
throw new ApplicationError('File does not seem to contain valid workflows.');
|
||||
throw new UserError('File does not seem to contain valid workflows.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -81,7 +81,7 @@ export class ImportWorkflowsCommand extends BaseCommand {
|
|||
}
|
||||
|
||||
if (flags.projectId && flags.userId) {
|
||||
throw new ApplicationError(
|
||||
throw new UserError(
|
||||
'You cannot use `--userId` and `--projectId` together. Use one or the other.',
|
||||
);
|
||||
}
|
||||
|
@ -93,7 +93,7 @@ export class ImportWorkflowsCommand extends BaseCommand {
|
|||
const result = await this.checkRelations(workflows, flags.projectId, flags.userId);
|
||||
|
||||
if (!result.success) {
|
||||
throw new ApplicationError(result.message);
|
||||
throw new UserError(result.message);
|
||||
}
|
||||
|
||||
this.logger.info(`Importing ${workflows.length} workflows...`);
|
||||
|
@ -220,7 +220,7 @@ export class ImportWorkflowsCommand extends BaseCommand {
|
|||
if (!userId) {
|
||||
const owner = await Container.get(UserRepository).findOneBy({ role: 'global:owner' });
|
||||
if (!owner) {
|
||||
throw new ApplicationError(`Failed to find owner. ${UM_FIX_INSTRUCTION}`);
|
||||
throw new UserError(`Failed to find owner. ${UM_FIX_INSTRUCTION}`);
|
||||
}
|
||||
userId = owner.id;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ import { Container } from '@n8n/di';
|
|||
// eslint-disable-next-line n8n-local-rules/misplaced-n8n-typeorm-import
|
||||
import { In } from '@n8n/typeorm';
|
||||
import { Flags } from '@oclif/core';
|
||||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { UserError } from 'n8n-workflow';
|
||||
|
||||
import { UM_FIX_INSTRUCTION } from '@/constants';
|
||||
import { CredentialsService } from '@/credentials/credentials.service';
|
||||
|
@ -56,7 +56,7 @@ export class Reset extends BaseCommand {
|
|||
Number(!!flags.deleteWorkflowsAndCredentials);
|
||||
|
||||
if (numberOfOptions !== 1) {
|
||||
throw new ApplicationError(wrongFlagsError);
|
||||
throw new UserError(wrongFlagsError);
|
||||
}
|
||||
|
||||
const owner = await this.getOwner();
|
||||
|
@ -71,13 +71,13 @@ export class Reset extends BaseCommand {
|
|||
// Migrate all workflows and credentials to another project.
|
||||
if (flags.projectId ?? flags.userId) {
|
||||
if (flags.userId && ldapIdentities.some((i) => i.userId === flags.userId)) {
|
||||
throw new ApplicationError(
|
||||
throw new UserError(
|
||||
`Can't migrate workflows and credentials to the user with the ID ${flags.userId}. That user was created via LDAP and will be deleted as well.`,
|
||||
);
|
||||
}
|
||||
|
||||
if (flags.projectId && personalProjectIds.includes(flags.projectId)) {
|
||||
throw new ApplicationError(
|
||||
throw new UserError(
|
||||
`Can't migrate workflows and credentials to the project with the ID ${flags.projectId}. That project is a personal project belonging to a user that was created via LDAP and will be deleted as well.`,
|
||||
);
|
||||
}
|
||||
|
@ -132,7 +132,7 @@ export class Reset extends BaseCommand {
|
|||
const project = await Container.get(ProjectRepository).findOneBy({ id: projectId });
|
||||
|
||||
if (project === null) {
|
||||
throw new ApplicationError(`Could not find the project with the ID ${projectId}.`);
|
||||
throw new UserError(`Could not find the project with the ID ${projectId}.`);
|
||||
}
|
||||
|
||||
return project;
|
||||
|
@ -142,7 +142,7 @@ export class Reset extends BaseCommand {
|
|||
const project = await Container.get(ProjectRepository).getPersonalProjectForUser(userId);
|
||||
|
||||
if (project === null) {
|
||||
throw new ApplicationError(
|
||||
throw new UserError(
|
||||
`Could not find the user with the ID ${userId} or their personalProject.`,
|
||||
);
|
||||
}
|
||||
|
@ -150,7 +150,7 @@ export class Reset extends BaseCommand {
|
|||
return project;
|
||||
}
|
||||
|
||||
throw new ApplicationError(wrongFlagsError);
|
||||
throw new UserError(wrongFlagsError);
|
||||
}
|
||||
|
||||
async catch(error: Error): Promise<void> {
|
||||
|
@ -161,7 +161,7 @@ export class Reset extends BaseCommand {
|
|||
private async getOwner() {
|
||||
const owner = await Container.get(UserRepository).findOneBy({ role: 'global:owner' });
|
||||
if (!owner) {
|
||||
throw new ApplicationError(`Failed to find owner. ${UM_FIX_INSTRUCTION}`);
|
||||
throw new UserError(`Failed to find owner. ${UM_FIX_INSTRUCTION}`);
|
||||
}
|
||||
|
||||
return owner;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { Container } from '@n8n/di';
|
||||
import { Flags } from '@oclif/core';
|
||||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { UserError } from 'n8n-workflow';
|
||||
|
||||
import { ActiveExecutions } from '@/active-executions';
|
||||
import config from '@/config';
|
||||
|
@ -84,9 +84,7 @@ export class Webhook extends BaseCommand {
|
|||
|
||||
async run() {
|
||||
if (this.globalConfig.multiMainSetup.enabled) {
|
||||
throw new ApplicationError(
|
||||
'Webhook process cannot be started when multi-main setup is enabled.',
|
||||
);
|
||||
throw new UserError('Webhook process cannot be started when multi-main setup is enabled.');
|
||||
}
|
||||
|
||||
const { ScalingService } = await import('@/scaling/scaling.service');
|
||||
|
|
|
@ -5,7 +5,7 @@ import { flatten } from 'flat';
|
|||
import { readFileSync } from 'fs';
|
||||
import merge from 'lodash/merge';
|
||||
import { Logger } from 'n8n-core';
|
||||
import { ApplicationError, setGlobalState } from 'n8n-workflow';
|
||||
import { setGlobalState, UserError } from 'n8n-workflow';
|
||||
import assert from 'node:assert';
|
||||
import colors from 'picocolors';
|
||||
|
||||
|
@ -84,7 +84,7 @@ if (!inE2ETests && !inTest) {
|
|||
} catch (error) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
||||
if (error.code === 'ENOENT') {
|
||||
throw new ApplicationError('File not found', { extra: { fileName } });
|
||||
throw new UserError('File not found', { extra: { fileName } });
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import type { SchemaObj } from 'convict';
|
||||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { UserError } from 'n8n-workflow';
|
||||
|
||||
import { NotStringArrayError } from '@/errors/not-string-array.error';
|
||||
|
||||
export const ensureStringArray = (values: string[], { env }: SchemaObj<string>) => {
|
||||
if (!env) throw new ApplicationError('Missing env', { extra: { env } });
|
||||
if (!env) throw new UserError('Missing env', { extra: { env } });
|
||||
|
||||
if (!Array.isArray(values)) throw new NotStringArrayError(env);
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ import Csrf from 'csrf';
|
|||
import type { Response } from 'express';
|
||||
import { Credentials, Logger } from 'n8n-core';
|
||||
import type { ICredentialDataDecryptedObject, IWorkflowExecuteAdditionalData } from 'n8n-workflow';
|
||||
import { jsonParse, ApplicationError } from 'n8n-workflow';
|
||||
import { jsonParse, UnexpectedError } from 'n8n-workflow';
|
||||
|
||||
import { RESPONSE_ERROR_MESSAGES, Time } from '@/constants';
|
||||
import { CredentialsHelper } from '@/credentials-helper';
|
||||
|
@ -171,7 +171,7 @@ export abstract class AbstractOAuthController {
|
|||
});
|
||||
|
||||
if (typeof decoded.cid !== 'string' || typeof decoded.token !== 'string') {
|
||||
throw new ApplicationError(errorMessage);
|
||||
throw new UnexpectedError(errorMessage);
|
||||
}
|
||||
|
||||
if (decoded.userId !== req.user?.id) {
|
||||
|
@ -201,7 +201,7 @@ export abstract class AbstractOAuthController {
|
|||
const state = this.decodeCsrfState(encodedState, req);
|
||||
const credential = await this.getCredentialWithoutUser(state.cid);
|
||||
if (!credential) {
|
||||
throw new ApplicationError('OAuth callback failed because of insufficient permissions');
|
||||
throw new UnexpectedError('OAuth callback failed because of insufficient permissions');
|
||||
}
|
||||
|
||||
const additionalData = await this.getAdditionalData();
|
||||
|
@ -216,7 +216,7 @@ export abstract class AbstractOAuthController {
|
|||
);
|
||||
|
||||
if (!this.verifyCsrfState(decryptedDataOriginal, state)) {
|
||||
throw new ApplicationError('The OAuth callback state is invalid!');
|
||||
throw new UnexpectedError('The OAuth callback state is invalid!');
|
||||
}
|
||||
|
||||
return [credential, decryptedDataOriginal, oauthCredentials];
|
||||
|
|
|
@ -26,7 +26,7 @@ import type {
|
|||
IExecuteData,
|
||||
IDataObject,
|
||||
} from 'n8n-workflow';
|
||||
import { ICredentialsHelper, NodeHelpers, Workflow, ApplicationError } from 'n8n-workflow';
|
||||
import { ICredentialsHelper, NodeHelpers, Workflow, UnexpectedError } from 'n8n-workflow';
|
||||
|
||||
import { CredentialTypes } from '@/credential-types';
|
||||
import { CredentialsOverwrites } from '@/credentials-overwrites';
|
||||
|
@ -65,7 +65,7 @@ const mockNodeTypes: INodeTypes = {
|
|||
},
|
||||
getByNameAndVersion(nodeType: string, version?: number): INodeType {
|
||||
if (!mockNodesData[nodeType]) {
|
||||
throw new ApplicationError(RESPONSE_ERROR_MESSAGES.NO_NODE, {
|
||||
throw new UnexpectedError(RESPONSE_ERROR_MESSAGES.NO_NODE, {
|
||||
tags: { nodeType },
|
||||
});
|
||||
}
|
||||
|
@ -245,7 +245,7 @@ export class CredentialsHelper extends ICredentialsHelper {
|
|||
type: string,
|
||||
): Promise<Credentials> {
|
||||
if (!nodeCredential.id) {
|
||||
throw new ApplicationError('Found credential with no ID.', {
|
||||
throw new UnexpectedError('Found credential with no ID.', {
|
||||
extra: { credentialName: nodeCredential.name },
|
||||
tags: { credentialType: type },
|
||||
});
|
||||
|
@ -276,7 +276,7 @@ export class CredentialsHelper extends ICredentialsHelper {
|
|||
const credentialTypeData = this.credentialTypes.getByName(type);
|
||||
|
||||
if (credentialTypeData === undefined) {
|
||||
throw new ApplicationError('Unknown credential type', { tags: { credentialType: type } });
|
||||
throw new UnexpectedError('Unknown credential type', { tags: { credentialType: type } });
|
||||
}
|
||||
|
||||
if (credentialTypeData.extends === undefined) {
|
||||
|
|
|
@ -15,7 +15,7 @@ import type {
|
|||
ICredentialType,
|
||||
INodeProperties,
|
||||
} from 'n8n-workflow';
|
||||
import { ApplicationError, CREDENTIAL_EMPTY_VALUE, deepCopy, NodeHelpers } from 'n8n-workflow';
|
||||
import { CREDENTIAL_EMPTY_VALUE, deepCopy, NodeHelpers, UnexpectedError } from 'n8n-workflow';
|
||||
|
||||
import { CREDENTIAL_BLANKING_VALUE } from '@/constants';
|
||||
import { CredentialTypes } from '@/credential-types';
|
||||
|
@ -405,7 +405,7 @@ export class CredentialsService {
|
|||
|
||||
// Safe guard in case the personal project does not exist for whatever reason.
|
||||
if (project === null) {
|
||||
throw new ApplicationError('No personal project found');
|
||||
throw new UnexpectedError('No personal project found');
|
||||
}
|
||||
|
||||
const newSharedCredential = this.sharedCredentialsRepository.create({
|
||||
|
|
|
@ -6,7 +6,7 @@ import type { PostgresConnectionOptions } from '@n8n/typeorm/driver/postgres/Pos
|
|||
import type { SqliteConnectionOptions } from '@n8n/typeorm/driver/sqlite/SqliteConnectionOptions';
|
||||
import type { SqlitePooledConnectionOptions } from '@n8n/typeorm/driver/sqlite-pooled/SqlitePooledConnectionOptions';
|
||||
import { InstanceSettings } from 'n8n-core';
|
||||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { UserError } from 'n8n-workflow';
|
||||
import path from 'path';
|
||||
import type { TlsOptions } from 'tls';
|
||||
|
||||
|
@ -129,7 +129,7 @@ export function getConnectionOptions(): DataSourceOptions {
|
|||
case 'mysqldb':
|
||||
return getMysqlConnectionOptions(dbType);
|
||||
default:
|
||||
throw new ApplicationError('Database type currently not supported', { extra: { dbType } });
|
||||
throw new UserError('Database type currently not supported', { extra: { dbType } });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import type { TableForeignKeyOptions, TableIndexOptions, QueryRunner } from '@n8n/typeorm';
|
||||
import { Table, TableColumn, TableForeignKey } from '@n8n/typeorm';
|
||||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { UnexpectedError } from 'n8n-workflow';
|
||||
import LazyPromise from 'p-lazy';
|
||||
|
||||
import { Column } from './column';
|
||||
|
@ -176,7 +176,7 @@ class ModifyNotNull extends TableOperation {
|
|||
async execute(queryRunner: QueryRunner) {
|
||||
const { tableName, prefix, columnName, isNullable } = this;
|
||||
const table = await queryRunner.getTable(`${prefix}${tableName}`);
|
||||
if (!table) throw new ApplicationError('No table found', { extra: { tableName } });
|
||||
if (!table) throw new UnexpectedError('No table found', { extra: { tableName } });
|
||||
const oldColumn = table.findColumnByName(columnName)!;
|
||||
const newColumn = oldColumn.clone();
|
||||
newColumn.isNullable = isNullable;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { UnexpectedError } from 'n8n-workflow';
|
||||
|
||||
import type { MigrationContext, ReversibleMigration } from '@/databases/types';
|
||||
|
||||
|
@ -41,7 +41,7 @@ export class AddGlobalAdminRole1700571993961 implements ReversibleMigration {
|
|||
|
||||
const memberRoleId = memberRoleIdResult[0]?.id;
|
||||
if (!memberRoleId) {
|
||||
throw new ApplicationError('Could not find global member role!');
|
||||
throw new UnexpectedError('Could not find global member role!');
|
||||
}
|
||||
|
||||
await runQuery(
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import type { ProjectRole } from '@n8n/api-types';
|
||||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { UserError } from 'n8n-workflow';
|
||||
import { nanoid } from 'nanoid';
|
||||
|
||||
import type { User } from '@/databases/entities/user';
|
||||
|
@ -249,7 +249,7 @@ export class CreateProject1714133768519 implements ReversibleMigration {
|
|||
const message =
|
||||
'Down migration only possible when there are no projects. Please delete all projects that were created via the UI first.';
|
||||
logger.error(message);
|
||||
throw new ApplicationError(message);
|
||||
throw new UserError(message);
|
||||
}
|
||||
|
||||
// 1. create temp table for shared workflows
|
||||
|
|
|
@ -23,7 +23,7 @@ import { DateUtils } from '@n8n/typeorm/util/DateUtils';
|
|||
import { parse, stringify } from 'flatted';
|
||||
import pick from 'lodash/pick';
|
||||
import { BinaryDataService, ErrorReporter, Logger } from 'n8n-core';
|
||||
import { ExecutionCancelledError, ApplicationError } from 'n8n-workflow';
|
||||
import { ExecutionCancelledError, UnexpectedError } from 'n8n-workflow';
|
||||
import type {
|
||||
AnnotationVote,
|
||||
ExecutionStatus,
|
||||
|
@ -206,7 +206,7 @@ export class ExecutionRepository extends Repository<ExecutionEntity> {
|
|||
if (executions.length === 0) return;
|
||||
|
||||
this.errorReporter.error(
|
||||
new ApplicationError('Found executions without executionData', {
|
||||
new UnexpectedError('Found executions without executionData', {
|
||||
extra: { executionIds: executions.map(({ id }) => id) },
|
||||
}),
|
||||
);
|
||||
|
@ -434,7 +434,7 @@ export class ExecutionRepository extends Repository<ExecutionEntity> {
|
|||
},
|
||||
) {
|
||||
if (!deleteConditions?.deleteBefore && !deleteConditions?.ids) {
|
||||
throw new ApplicationError(
|
||||
throw new UnexpectedError(
|
||||
'Either "deleteBefore" or "ids" must be present in the request body',
|
||||
);
|
||||
}
|
||||
|
@ -836,7 +836,7 @@ export class ExecutionRepository extends Repository<ExecutionEntity> {
|
|||
|
||||
async findManyByRangeQuery(query: ExecutionSummaries.RangeQuery): Promise<ExecutionSummary[]> {
|
||||
if (query?.accessibleWorkflowIds?.length === 0) {
|
||||
throw new ApplicationError('Expected accessible workflow IDs');
|
||||
throw new UnexpectedError('Expected accessible workflow IDs');
|
||||
}
|
||||
|
||||
// Due to performance reasons, we use custom query builder with raw SQL.
|
||||
|
|
|
@ -2,7 +2,7 @@ import { Container } from '@n8n/di';
|
|||
import type { EntitySubscriberInterface, UpdateEvent } from '@n8n/typeorm';
|
||||
import { EventSubscriber } from '@n8n/typeorm';
|
||||
import { ErrorReporter, Logger } from 'n8n-core';
|
||||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { UnexpectedError } from 'n8n-workflow';
|
||||
|
||||
import { Project } from '../entities/project';
|
||||
import { User } from '../entities/user';
|
||||
|
@ -47,7 +47,7 @@ export class UserSubscriber implements EntitySubscriberInterface<User> {
|
|||
// that this could cause further data inconsistencies.
|
||||
const message = "Could not update the personal project's name";
|
||||
Container.get(Logger).warn(message, event.entity);
|
||||
const exception = new ApplicationError(message);
|
||||
const exception = new UnexpectedError(message);
|
||||
this.eventReporter.warn(exception, event.entity);
|
||||
return;
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ export class UserSubscriber implements EntitySubscriberInterface<User> {
|
|||
// that this could cause further data inconsistencies.
|
||||
const message = "Could not update the personal project's name";
|
||||
Container.get(Logger).warn(message, event.entity);
|
||||
const exception = new ApplicationError(message);
|
||||
const exception = new UnexpectedError(message);
|
||||
this.eventReporter.warn(exception, event.entity);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import type { ObjectLiteral } from '@n8n/typeorm';
|
|||
import type { QueryRunner } from '@n8n/typeorm/query-runner/QueryRunner';
|
||||
import { readFileSync, rmSync } from 'fs';
|
||||
import { InstanceSettings, Logger } from 'n8n-core';
|
||||
import { ApplicationError, jsonParse } from 'n8n-workflow';
|
||||
import { jsonParse, UnexpectedError } from 'n8n-workflow';
|
||||
|
||||
import { inTest } from '@/constants';
|
||||
import { createSchemaBuilder } from '@/databases/dsl';
|
||||
|
@ -23,7 +23,7 @@ function loadSurveyFromDisk(): string | null {
|
|||
const personalizationSurvey = JSON.parse(surveyFile) as object;
|
||||
const kvPairs = Object.entries(personalizationSurvey);
|
||||
if (!kvPairs.length) {
|
||||
throw new ApplicationError('personalizationSurvey is empty');
|
||||
throw new UnexpectedError('personalizationSurvey is empty');
|
||||
} else {
|
||||
const emptyKeys = kvPairs.reduce((acc, [, value]) => {
|
||||
if (!value || (Array.isArray(value) && !value.length)) {
|
||||
|
@ -32,7 +32,7 @@ function loadSurveyFromDisk(): string | null {
|
|||
return acc;
|
||||
}, 0);
|
||||
if (emptyKeys === kvPairs.length) {
|
||||
throw new ApplicationError('incomplete personalizationSurvey');
|
||||
throw new UnexpectedError('incomplete personalizationSurvey');
|
||||
}
|
||||
}
|
||||
return surveyFile;
|
||||
|
@ -69,7 +69,7 @@ const runDisablingForeignKeys = async (
|
|||
) => {
|
||||
const { dbType, queryRunner } = context;
|
||||
if (dbType !== 'sqlite')
|
||||
throw new ApplicationError('Disabling transactions only available in sqlite');
|
||||
throw new UnexpectedError('Disabling transactions only available in sqlite');
|
||||
await queryRunner.query('PRAGMA foreign_keys=OFF');
|
||||
await queryRunner.startTransaction();
|
||||
try {
|
||||
|
@ -195,7 +195,7 @@ export const wrapMigration = (migration: Migration) => {
|
|||
},
|
||||
});
|
||||
} else {
|
||||
throw new ApplicationError(`Migration "${migration.name}" is missing the method \`up\`.`);
|
||||
throw new UnexpectedError(`Migration "${migration.name}" is missing the method \`up\`.`);
|
||||
}
|
||||
if (down) {
|
||||
Object.assign(migration.prototype, {
|
||||
|
|
|
@ -3,7 +3,7 @@ import { Container, Service } from '@n8n/di';
|
|||
import { Router } from 'express';
|
||||
import type { Application, Request, Response, RequestHandler } from 'express';
|
||||
import { rateLimit as expressRateLimit } from 'express-rate-limit';
|
||||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { UnexpectedError } from 'n8n-workflow';
|
||||
import type { ZodClass } from 'zod-class';
|
||||
|
||||
import { AuthService } from '@/auth/auth.service';
|
||||
|
@ -100,7 +100,7 @@ export class ControllerRegistry {
|
|||
return res.status(400).json(output.error.errors[0]);
|
||||
}
|
||||
}
|
||||
} else throw new ApplicationError('Unknown arg type: ' + arg.type);
|
||||
} else throw new UnexpectedError('Unknown arg type: ' + arg.type);
|
||||
}
|
||||
return await controller[handlerName](...args);
|
||||
};
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { Container } from '@n8n/di';
|
||||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { UnexpectedError } from 'n8n-workflow';
|
||||
|
||||
import { DEFAULT_SHUTDOWN_PRIORITY } from '@/constants';
|
||||
import { type ServiceClass, ShutdownService } from '@/shutdown/shutdown.service';
|
||||
|
@ -33,7 +33,7 @@ export const OnShutdown =
|
|||
Container.get(ShutdownService).register(priority, { serviceClass, methodName });
|
||||
} else {
|
||||
const name = `${serviceClass.name}.${methodName}()`;
|
||||
throw new ApplicationError(
|
||||
throw new UnexpectedError(
|
||||
`${name} must be a method on ${serviceClass.name} to use "OnShutdown"`,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ import type { SourceControlledFile } from '@n8n/api-types';
|
|||
import { Service } from '@n8n/di';
|
||||
import { rmSync } from 'fs';
|
||||
import { Credentials, InstanceSettings, Logger } from 'n8n-core';
|
||||
import { ApplicationError, type ICredentialDataDecryptedObject } from 'n8n-workflow';
|
||||
import { UnexpectedError, type ICredentialDataDecryptedObject } from 'n8n-workflow';
|
||||
import { writeFile as fsWriteFile, rm as fsRm } from 'node:fs/promises';
|
||||
import path from 'path';
|
||||
|
||||
|
@ -120,7 +120,7 @@ export class SourceControlExportService {
|
|||
const project = sharedWorkflow.project;
|
||||
|
||||
if (!project) {
|
||||
throw new ApplicationError(
|
||||
throw new UnexpectedError(
|
||||
`Workflow ${formatWorkflow(sharedWorkflow.workflow)} has no owner`,
|
||||
);
|
||||
}
|
||||
|
@ -130,7 +130,7 @@ export class SourceControlExportService {
|
|||
(pr) => pr.role === 'project:personalOwner',
|
||||
);
|
||||
if (!ownerRelation) {
|
||||
throw new ApplicationError(
|
||||
throw new UnexpectedError(
|
||||
`Workflow ${formatWorkflow(sharedWorkflow.workflow)} has no owner`,
|
||||
);
|
||||
}
|
||||
|
@ -145,7 +145,7 @@ export class SourceControlExportService {
|
|||
teamName: project.name,
|
||||
};
|
||||
} else {
|
||||
throw new ApplicationError(
|
||||
throw new UnexpectedError(
|
||||
`Workflow belongs to unknown project type: ${project.type as string}`,
|
||||
);
|
||||
}
|
||||
|
@ -164,8 +164,8 @@ export class SourceControlExportService {
|
|||
})),
|
||||
};
|
||||
} catch (error) {
|
||||
if (error instanceof ApplicationError) throw error;
|
||||
throw new ApplicationError('Failed to export workflows to work folder', { cause: error });
|
||||
if (error instanceof UnexpectedError) throw error;
|
||||
throw new UnexpectedError('Failed to export workflows to work folder', { cause: error });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -195,7 +195,7 @@ export class SourceControlExportService {
|
|||
],
|
||||
};
|
||||
} catch (error) {
|
||||
throw new ApplicationError('Failed to export variables to work folder', {
|
||||
throw new UnexpectedError('Failed to export variables to work folder', {
|
||||
cause: error,
|
||||
});
|
||||
}
|
||||
|
@ -237,7 +237,7 @@ export class SourceControlExportService {
|
|||
],
|
||||
};
|
||||
} catch (error) {
|
||||
throw new ApplicationError('Failed to export variables to work folder', { cause: error });
|
||||
throw new UnexpectedError('Failed to export variables to work folder', { cause: error });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -336,7 +336,7 @@ export class SourceControlExportService {
|
|||
missingIds,
|
||||
};
|
||||
} catch (error) {
|
||||
throw new ApplicationError('Failed to export credentials to work folder', { cause: error });
|
||||
throw new UnexpectedError('Failed to export credentials to work folder', { cause: error });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { Service } from '@n8n/di';
|
||||
import { execSync } from 'child_process';
|
||||
import { Logger } from 'n8n-core';
|
||||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { UnexpectedError } from 'n8n-workflow';
|
||||
import path from 'path';
|
||||
import type {
|
||||
CommitResult,
|
||||
|
@ -51,7 +51,7 @@ export class SourceControlGitService {
|
|||
});
|
||||
this.logger.debug(`Git binary found: ${gitResult.toString()}`);
|
||||
} catch (error) {
|
||||
throw new ApplicationError('Git binary not found', { cause: error });
|
||||
throw new UnexpectedError('Git binary not found', { cause: error });
|
||||
}
|
||||
try {
|
||||
const sshResult = execSync('ssh -V', {
|
||||
|
@ -59,7 +59,7 @@ export class SourceControlGitService {
|
|||
});
|
||||
this.logger.debug(`SSH binary found: ${sshResult.toString()}`);
|
||||
} catch (error) {
|
||||
throw new ApplicationError('SSH binary not found', { cause: error });
|
||||
throw new UnexpectedError('SSH binary not found', { cause: error });
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -126,7 +126,7 @@ export class SourceControlGitService {
|
|||
|
||||
private async checkRepositorySetup(): Promise<boolean> {
|
||||
if (!this.git) {
|
||||
throw new ApplicationError('Git is not initialized (async)');
|
||||
throw new UnexpectedError('Git is not initialized (async)');
|
||||
}
|
||||
if (!(await this.git.checkIsRepo())) {
|
||||
return false;
|
||||
|
@ -141,7 +141,7 @@ export class SourceControlGitService {
|
|||
|
||||
private async hasRemote(remote: string): Promise<boolean> {
|
||||
if (!this.git) {
|
||||
throw new ApplicationError('Git is not initialized (async)');
|
||||
throw new UnexpectedError('Git is not initialized (async)');
|
||||
}
|
||||
try {
|
||||
const remotes = await this.git.getRemotes(true);
|
||||
|
@ -153,7 +153,7 @@ export class SourceControlGitService {
|
|||
return true;
|
||||
}
|
||||
} catch (error) {
|
||||
throw new ApplicationError('Git is not initialized', { cause: error });
|
||||
throw new UnexpectedError('Git is not initialized', { cause: error });
|
||||
}
|
||||
this.logger.debug(`Git remote not found: ${remote}`);
|
||||
return false;
|
||||
|
@ -167,7 +167,7 @@ export class SourceControlGitService {
|
|||
user: User,
|
||||
): Promise<void> {
|
||||
if (!this.git) {
|
||||
throw new ApplicationError('Git is not initialized (Promise)');
|
||||
throw new UnexpectedError('Git is not initialized (Promise)');
|
||||
}
|
||||
if (sourceControlPreferences.initRepo) {
|
||||
try {
|
||||
|
@ -231,7 +231,7 @@ export class SourceControlGitService {
|
|||
|
||||
async setGitUserDetails(name: string, email: string): Promise<void> {
|
||||
if (!this.git) {
|
||||
throw new ApplicationError('Git is not initialized (setGitUserDetails)');
|
||||
throw new UnexpectedError('Git is not initialized (setGitUserDetails)');
|
||||
}
|
||||
await this.git.addConfig('user.email', email);
|
||||
await this.git.addConfig('user.name', name);
|
||||
|
@ -239,7 +239,7 @@ export class SourceControlGitService {
|
|||
|
||||
async getBranches(): Promise<{ branches: string[]; currentBranch: string }> {
|
||||
if (!this.git) {
|
||||
throw new ApplicationError('Git is not initialized (getBranches)');
|
||||
throw new UnexpectedError('Git is not initialized (getBranches)');
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -256,13 +256,13 @@ export class SourceControlGitService {
|
|||
currentBranch: current,
|
||||
};
|
||||
} catch (error) {
|
||||
throw new ApplicationError('Could not get remote branches from repository', { cause: error });
|
||||
throw new UnexpectedError('Could not get remote branches from repository', { cause: error });
|
||||
}
|
||||
}
|
||||
|
||||
async setBranch(branch: string): Promise<{ branches: string[]; currentBranch: string }> {
|
||||
if (!this.git) {
|
||||
throw new ApplicationError('Git is not initialized (setBranch)');
|
||||
throw new UnexpectedError('Git is not initialized (setBranch)');
|
||||
}
|
||||
await this.git.checkout(branch);
|
||||
await this.git.branch([`--set-upstream-to=${SOURCE_CONTROL_ORIGIN}/${branch}`, branch]);
|
||||
|
@ -271,7 +271,7 @@ export class SourceControlGitService {
|
|||
|
||||
async getCurrentBranch(): Promise<{ current: string; remote: string }> {
|
||||
if (!this.git) {
|
||||
throw new ApplicationError('Git is not initialized (getCurrentBranch)');
|
||||
throw new UnexpectedError('Git is not initialized (getCurrentBranch)');
|
||||
}
|
||||
const currentBranch = (await this.git.branch()).current;
|
||||
return {
|
||||
|
@ -282,7 +282,7 @@ export class SourceControlGitService {
|
|||
|
||||
async diffRemote(): Promise<DiffResult | undefined> {
|
||||
if (!this.git) {
|
||||
throw new ApplicationError('Git is not initialized (diffRemote)');
|
||||
throw new UnexpectedError('Git is not initialized (diffRemote)');
|
||||
}
|
||||
const currentBranch = await this.getCurrentBranch();
|
||||
if (currentBranch.remote) {
|
||||
|
@ -294,7 +294,7 @@ export class SourceControlGitService {
|
|||
|
||||
async diffLocal(): Promise<DiffResult | undefined> {
|
||||
if (!this.git) {
|
||||
throw new ApplicationError('Git is not initialized (diffLocal)');
|
||||
throw new UnexpectedError('Git is not initialized (diffLocal)');
|
||||
}
|
||||
const currentBranch = await this.getCurrentBranch();
|
||||
if (currentBranch.remote) {
|
||||
|
@ -306,7 +306,7 @@ export class SourceControlGitService {
|
|||
|
||||
async fetch(): Promise<FetchResult> {
|
||||
if (!this.git) {
|
||||
throw new ApplicationError('Git is not initialized (fetch)');
|
||||
throw new UnexpectedError('Git is not initialized (fetch)');
|
||||
}
|
||||
await this.setGitSshCommand();
|
||||
return await this.git.fetch();
|
||||
|
@ -314,7 +314,7 @@ export class SourceControlGitService {
|
|||
|
||||
async pull(options: { ffOnly: boolean } = { ffOnly: true }): Promise<PullResult> {
|
||||
if (!this.git) {
|
||||
throw new ApplicationError('Git is not initialized (pull)');
|
||||
throw new UnexpectedError('Git is not initialized (pull)');
|
||||
}
|
||||
await this.setGitSshCommand();
|
||||
const params = {};
|
||||
|
@ -332,7 +332,7 @@ export class SourceControlGitService {
|
|||
): Promise<PushResult> {
|
||||
const { force, branch } = options;
|
||||
if (!this.git) {
|
||||
throw new ApplicationError('Git is not initialized ({)');
|
||||
throw new UnexpectedError('Git is not initialized ({)');
|
||||
}
|
||||
await this.setGitSshCommand();
|
||||
if (force) {
|
||||
|
@ -343,7 +343,7 @@ export class SourceControlGitService {
|
|||
|
||||
async stage(files: Set<string>, deletedFiles?: Set<string>): Promise<string> {
|
||||
if (!this.git) {
|
||||
throw new ApplicationError('Git is not initialized (stage)');
|
||||
throw new UnexpectedError('Git is not initialized (stage)');
|
||||
}
|
||||
if (deletedFiles?.size) {
|
||||
try {
|
||||
|
@ -359,7 +359,7 @@ export class SourceControlGitService {
|
|||
options: { hard: boolean; target: string } = { hard: true, target: 'HEAD' },
|
||||
): Promise<string> {
|
||||
if (!this.git) {
|
||||
throw new ApplicationError('Git is not initialized (Promise)');
|
||||
throw new UnexpectedError('Git is not initialized (Promise)');
|
||||
}
|
||||
if (options?.hard) {
|
||||
return await this.git.raw(['reset', '--hard', options.target]);
|
||||
|
@ -371,14 +371,14 @@ export class SourceControlGitService {
|
|||
|
||||
async commit(message: string): Promise<CommitResult> {
|
||||
if (!this.git) {
|
||||
throw new ApplicationError('Git is not initialized (commit)');
|
||||
throw new UnexpectedError('Git is not initialized (commit)');
|
||||
}
|
||||
return await this.git.commit(message);
|
||||
}
|
||||
|
||||
async status(): Promise<StatusResult> {
|
||||
if (!this.git) {
|
||||
throw new ApplicationError('Git is not initialized (status)');
|
||||
throw new UnexpectedError('Git is not initialized (status)');
|
||||
}
|
||||
const statusResult = await this.git.status();
|
||||
return statusResult;
|
||||
|
|
|
@ -3,7 +3,7 @@ import { Container } from '@n8n/di';
|
|||
import { generateKeyPairSync } from 'crypto';
|
||||
import { constants as fsConstants, mkdirSync, accessSync } from 'fs';
|
||||
import { Logger } from 'n8n-core';
|
||||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { UserError } from 'n8n-workflow';
|
||||
import { ok } from 'node:assert/strict';
|
||||
import path from 'path';
|
||||
|
||||
|
@ -171,7 +171,7 @@ export function getTrackingInformationFromPostPushResult(result: SourceControlle
|
|||
* Normalizes and validates the given source controlled file path. Ensures
|
||||
* the path is absolute and contained within the git folder.
|
||||
*
|
||||
* @throws {ApplicationError} If the path is not within the git folder
|
||||
* @throws {UserError} If the path is not within the git folder
|
||||
*/
|
||||
export function normalizeAndValidateSourceControlledFilePath(
|
||||
gitFolderPath: string,
|
||||
|
@ -182,7 +182,7 @@ export function normalizeAndValidateSourceControlledFilePath(
|
|||
const normalizedPath = path.isAbsolute(filePath) ? filePath : path.join(gitFolderPath, filePath);
|
||||
|
||||
if (!isContainedWithin(gitFolderPath, filePath)) {
|
||||
throw new ApplicationError(`File path ${filePath} is invalid`);
|
||||
throw new UserError(`File path ${filePath} is invalid`);
|
||||
}
|
||||
|
||||
return normalizedPath;
|
||||
|
|
|
@ -4,7 +4,7 @@ import { Service } from '@n8n/di';
|
|||
import { In } from '@n8n/typeorm';
|
||||
import glob from 'fast-glob';
|
||||
import { Credentials, ErrorReporter, InstanceSettings, Logger } from 'n8n-core';
|
||||
import { ApplicationError, jsonParse, ensureError } from 'n8n-workflow';
|
||||
import { jsonParse, ensureError, UserError, UnexpectedError } from 'n8n-workflow';
|
||||
import { readFile as fsReadFile } from 'node:fs/promises';
|
||||
import path from 'path';
|
||||
|
||||
|
@ -250,7 +250,7 @@ export class SourceControlImportService {
|
|||
this.logger.debug(`Updating workflow id ${importedWorkflow.id ?? 'new'}`);
|
||||
const upsertResult = await this.workflowRepository.upsert({ ...importedWorkflow }, ['id']);
|
||||
if (upsertResult?.identifiers?.length !== 1) {
|
||||
throw new ApplicationError('Failed to upsert workflow', {
|
||||
throw new UnexpectedError('Failed to upsert workflow', {
|
||||
extra: { workflowId: importedWorkflow.id ?? 'new' },
|
||||
});
|
||||
}
|
||||
|
@ -411,7 +411,7 @@ export class SourceControlImportService {
|
|||
select: ['id'],
|
||||
});
|
||||
if (findByName && findByName.id !== tag.id) {
|
||||
throw new ApplicationError(
|
||||
throw new UserError(
|
||||
`A tag with the name <strong>${tag.name}</strong> already exists locally.<br />Please either rename the local tag, or the remote one with the id <strong>${tag.id}</strong> in the tags.json file.`,
|
||||
);
|
||||
}
|
||||
|
@ -570,7 +570,7 @@ export class SourceControlImportService {
|
|||
assertNever(owner);
|
||||
|
||||
const errorOwner = owner as ResourceOwner;
|
||||
throw new ApplicationError(
|
||||
throw new UnexpectedError(
|
||||
`Unknown resource owner type "${
|
||||
typeof errorOwner !== 'string' ? errorOwner.type : 'UNKNOWN'
|
||||
}" found when importing from source controller`,
|
||||
|
|
|
@ -3,7 +3,7 @@ import type { ValidationError } from 'class-validator';
|
|||
import { validate } from 'class-validator';
|
||||
import { rm as fsRm } from 'fs/promises';
|
||||
import { Cipher, InstanceSettings, Logger } from 'n8n-core';
|
||||
import { ApplicationError, jsonParse } from 'n8n-workflow';
|
||||
import { jsonParse, UnexpectedError } from 'n8n-workflow';
|
||||
import { writeFile, chmod, readFile } from 'node:fs/promises';
|
||||
import path from 'path';
|
||||
|
||||
|
@ -78,7 +78,7 @@ export class SourceControlPreferencesService {
|
|||
private async getPrivateKeyFromDatabase() {
|
||||
const dbKeyPair = await this.getKeyPairFromDatabase();
|
||||
|
||||
if (!dbKeyPair) throw new ApplicationError('Failed to find key pair in database');
|
||||
if (!dbKeyPair) throw new UnexpectedError('Failed to find key pair in database');
|
||||
|
||||
return this.cipher.decrypt(dbKeyPair.encryptedPrivateKey);
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ export class SourceControlPreferencesService {
|
|||
private async getPublicKeyFromDatabase() {
|
||||
const dbKeyPair = await this.getKeyPairFromDatabase();
|
||||
|
||||
if (!dbKeyPair) throw new ApplicationError('Failed to find key pair in database');
|
||||
if (!dbKeyPair) throw new UnexpectedError('Failed to find key pair in database');
|
||||
|
||||
return dbKeyPair.publicKey;
|
||||
}
|
||||
|
@ -147,7 +147,7 @@ export class SourceControlPreferencesService {
|
|||
loadOnStartup: true,
|
||||
});
|
||||
} catch (error) {
|
||||
throw new ApplicationError('Failed to write key pair to database', { cause: error });
|
||||
throw new UnexpectedError('Failed to write key pair to database', { cause: error });
|
||||
}
|
||||
|
||||
// update preferences only after generating key pair to prevent endless loop
|
||||
|
@ -190,7 +190,7 @@ export class SourceControlPreferencesService {
|
|||
validationError: { target: false },
|
||||
});
|
||||
if (validationResult.length > 0) {
|
||||
throw new ApplicationError('Invalid source control preferences', {
|
||||
throw new UnexpectedError('Invalid source control preferences', {
|
||||
extra: { preferences: validationResult },
|
||||
});
|
||||
}
|
||||
|
@ -218,7 +218,7 @@ export class SourceControlPreferencesService {
|
|||
{ transaction: false },
|
||||
);
|
||||
} catch (error) {
|
||||
throw new ApplicationError('Failed to save source control preferences', { cause: error });
|
||||
throw new UnexpectedError('Failed to save source control preferences', { cause: error });
|
||||
}
|
||||
}
|
||||
return this.sourceControlPreferences;
|
||||
|
|
|
@ -6,7 +6,7 @@ import type {
|
|||
import { Service } from '@n8n/di';
|
||||
import { writeFileSync } from 'fs';
|
||||
import { Logger } from 'n8n-core';
|
||||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { UnexpectedError, UserError } from 'n8n-workflow';
|
||||
import path from 'path';
|
||||
import type { PushResult } from 'simple-git';
|
||||
|
||||
|
@ -90,7 +90,7 @@ export class SourceControlService {
|
|||
false,
|
||||
);
|
||||
if (!foldersExisted) {
|
||||
throw new ApplicationError('No folders exist');
|
||||
throw new UserError('No folders exist');
|
||||
}
|
||||
if (!this.gitService.git) {
|
||||
await this.initGitService();
|
||||
|
@ -101,7 +101,7 @@ export class SourceControlService {
|
|||
branches.current !==
|
||||
this.sourceControlPreferencesService.sourceControlPreferences.branchName
|
||||
) {
|
||||
throw new ApplicationError('Branch is not set up correctly');
|
||||
throw new UserError('Branch is not set up correctly');
|
||||
}
|
||||
} catch (error) {
|
||||
throw new BadRequestError(
|
||||
|
@ -123,7 +123,7 @@ export class SourceControlService {
|
|||
this.gitService.resetService();
|
||||
return this.sourceControlPreferencesService.sourceControlPreferences;
|
||||
} catch (error) {
|
||||
throw new ApplicationError('Failed to disconnect from source control', { cause: error });
|
||||
throw new UnexpectedError('Failed to disconnect from source control', { cause: error });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -202,7 +202,7 @@ export class SourceControlService {
|
|||
await this.gitService.pull();
|
||||
} catch (error) {
|
||||
this.logger.error(`Failed to reset workfolder: ${(error as Error).message}`);
|
||||
throw new ApplicationError(
|
||||
throw new UserError(
|
||||
'Unable to fetch updates from git - your folder might be out of sync. Try reconnecting from the Source Control settings page.',
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { UnexpectedError } from 'n8n-workflow';
|
||||
|
||||
export class AbortedExecutionRetryError extends ApplicationError {
|
||||
export class AbortedExecutionRetryError extends UnexpectedError {
|
||||
constructor() {
|
||||
super('The execution was aborted before starting, so it cannot be retried', {
|
||||
level: 'warning',
|
||||
});
|
||||
super('The execution was aborted before starting, so it cannot be retried');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { UnexpectedError } from 'n8n-workflow';
|
||||
|
||||
export class MalformedRefreshValueError extends ApplicationError {
|
||||
export class MalformedRefreshValueError extends UnexpectedError {
|
||||
constructor() {
|
||||
super('Refresh value must have the same number of values as keys');
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { UnexpectedError } from 'n8n-workflow';
|
||||
|
||||
export class UncacheableValueError extends ApplicationError {
|
||||
export class UncacheableValueError extends UnexpectedError {
|
||||
constructor(key: string) {
|
||||
super('Value cannot be cached in Redis', {
|
||||
extra: { key, hint: 'Does the value contain circular references?' },
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { UserError } from 'n8n-workflow';
|
||||
|
||||
export class CredentialNotFoundError extends ApplicationError {
|
||||
export class CredentialNotFoundError extends UserError {
|
||||
constructor(credentialId: string, credentialType: string) {
|
||||
super(`Credential with ID "${credentialId}" does not exist for type "${credentialType}".`);
|
||||
this.level = 'warning';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { UserError } from 'n8n-workflow';
|
||||
|
||||
export class CredentialsOverwritesAlreadySetError extends ApplicationError {
|
||||
export class CredentialsOverwritesAlreadySetError extends UserError {
|
||||
constructor() {
|
||||
super('Credentials overwrites may not be set more than once.');
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { UnexpectedError } from 'n8n-workflow';
|
||||
|
||||
export class DeduplicationError extends ApplicationError {
|
||||
export class DeduplicationError extends UnexpectedError {
|
||||
constructor(message: string) {
|
||||
super(`Deduplication Failed: ${message}`);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { UnexpectedError } from 'n8n-workflow';
|
||||
|
||||
export class ExecutionNotFoundError extends ApplicationError {
|
||||
export class ExecutionNotFoundError extends UnexpectedError {
|
||||
constructor(executionId: string) {
|
||||
super('No active execution found', { extra: { executionId } });
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { UnexpectedError } from 'n8n-workflow';
|
||||
|
||||
export class ExternalSecretsProviderNotFoundError extends ApplicationError {
|
||||
export class ExternalSecretsProviderNotFoundError extends UnexpectedError {
|
||||
constructor(public providerName: string) {
|
||||
super(`External secrets provider not found: ${providerName}`);
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { UserError } from 'n8n-workflow';
|
||||
|
||||
import type { LICENSE_FEATURES } from '@/constants';
|
||||
|
||||
export class FeatureNotLicensedError extends ApplicationError {
|
||||
export class FeatureNotLicensedError extends UserError {
|
||||
constructor(feature: (typeof LICENSE_FEATURES)[keyof typeof LICENSE_FEATURES]) {
|
||||
super(
|
||||
`Your license does not allow for ${feature}. To enable ${feature}, please upgrade to a license that supports this feature.`,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { UserError } from 'n8n-workflow';
|
||||
|
||||
export class InvalidConcurrencyLimitError extends ApplicationError {
|
||||
export class InvalidConcurrencyLimitError extends UserError {
|
||||
constructor(value: number) {
|
||||
super('Concurrency limit set to invalid value', { level: 'warning', extra: { value } });
|
||||
super('Concurrency limit set to invalid value', { extra: { value } });
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { UnexpectedError } from 'n8n-workflow';
|
||||
|
||||
export class InvalidRoleError extends ApplicationError {}
|
||||
export class InvalidRoleError extends UnexpectedError {}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { OperationalError } from 'n8n-workflow';
|
||||
|
||||
/**
|
||||
* @docs https://docs.bullmq.io/guide/workers/stalled-jobs
|
||||
*/
|
||||
export class MaxStalledCountError extends ApplicationError {
|
||||
export class MaxStalledCountError extends OperationalError {
|
||||
constructor(cause: Error) {
|
||||
super(
|
||||
'This execution failed to be processed too many times and will no longer retry. To allow this execution to complete, please break down your workflow or scale up your workers or adjust your worker settings.',
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { UserError } from 'n8n-workflow';
|
||||
|
||||
export class MissingExecutionStopError extends ApplicationError {
|
||||
export class MissingExecutionStopError extends UserError {
|
||||
constructor(executionId: string) {
|
||||
super('Failed to find execution to stop', { extra: { executionId } });
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { UserError } from 'n8n-workflow';
|
||||
|
||||
export class NonJsonBodyError extends ApplicationError {
|
||||
export class NonJsonBodyError extends UserError {
|
||||
constructor() {
|
||||
super('Body must be valid JSON. Please make sure `content-type` is `application/json`.');
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { UserError } from 'n8n-workflow';
|
||||
|
||||
export class NotStringArrayError extends ApplicationError {
|
||||
export class NotStringArrayError extends UserError {
|
||||
constructor(env: string) {
|
||||
super(`${env} is not a string array.`);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { UnexpectedError } from 'n8n-workflow';
|
||||
|
||||
export class PostgresLiveRowsRetrievalError extends ApplicationError {
|
||||
export class PostgresLiveRowsRetrievalError extends UnexpectedError {
|
||||
constructor(rows: unknown) {
|
||||
super('Failed to retrieve live execution rows in Postgres', { extra: { rows } });
|
||||
}
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { UnexpectedError } from 'n8n-workflow';
|
||||
|
||||
export class QueuedExecutionRetryError extends ApplicationError {
|
||||
export class QueuedExecutionRetryError extends UnexpectedError {
|
||||
constructor() {
|
||||
super('Execution is queued to run (not yet started) so it cannot be retried', {
|
||||
level: 'warning',
|
||||
});
|
||||
super('Execution is queued to run (not yet started) so it cannot be retried');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { UnexpectedError } from 'n8n-workflow';
|
||||
|
||||
export class RedactableError extends ApplicationError {
|
||||
export class RedactableError extends UnexpectedError {
|
||||
constructor(fieldName: string, args: string) {
|
||||
super(
|
||||
`Failed to find "${fieldName}" property in argument "${args.toString()}". Please set the decorator \`@Redactable()\` only on \`LogStreamingEventRelay\` methods where the argument contains a "${fieldName}" property.`,
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { BaseError } from 'n8n-workflow';
|
||||
|
||||
/**
|
||||
* Special Error which allows to return also an error code and http status code
|
||||
*/
|
||||
export abstract class ResponseError extends ApplicationError {
|
||||
export abstract class ResponseError extends BaseError {
|
||||
/**
|
||||
* Creates an instance of ResponseError.
|
||||
* Must be used inside a block with `ResponseHelper.send()`.
|
||||
|
@ -20,5 +20,13 @@ export abstract class ResponseError extends ApplicationError {
|
|||
) {
|
||||
super(message, { cause });
|
||||
this.name = 'ResponseError';
|
||||
|
||||
if (httpStatusCode >= 400 && httpStatusCode < 500) {
|
||||
this.level = 'warning'; // client errors (4xx)
|
||||
} else if (httpStatusCode >= 502 && httpStatusCode <= 504) {
|
||||
this.level = 'info'; // transient errors (502, 503, 504)
|
||||
} else {
|
||||
this.level = 'error'; // other 5xx
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { UserError } from 'n8n-workflow';
|
||||
|
||||
export class SharedWorkflowNotFoundError extends ApplicationError {}
|
||||
export class SharedWorkflowNotFoundError extends UserError {}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { UnexpectedError } from 'n8n-workflow';
|
||||
|
||||
export class UnknownAuthTypeError extends ApplicationError {
|
||||
export class UnknownAuthTypeError extends UnexpectedError {
|
||||
constructor(authType: string) {
|
||||
super('Unknown auth type', { extra: { authType } });
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { UnexpectedError } from 'n8n-workflow';
|
||||
|
||||
export class UnknownExecutionModeError extends ApplicationError {
|
||||
export class UnknownExecutionModeError extends UnexpectedError {
|
||||
constructor(mode: string) {
|
||||
super('Unknown execution mode', { extra: { mode } });
|
||||
}
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { UserError } from 'n8n-workflow';
|
||||
|
||||
export class VariableCountLimitReachedError extends ApplicationError {}
|
||||
export class VariableCountLimitReachedError extends UserError {}
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { UnexpectedError } from 'n8n-workflow';
|
||||
|
||||
export class VariableValidationError extends ApplicationError {}
|
||||
export class VariableValidationError extends UnexpectedError {}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { UserError } from 'n8n-workflow';
|
||||
|
||||
export class WorkerMissingEncryptionKey extends ApplicationError {
|
||||
export class WorkerMissingEncryptionKey extends UserError {
|
||||
constructor() {
|
||||
super(
|
||||
[
|
||||
|
@ -8,7 +8,6 @@ export class WorkerMissingEncryptionKey extends ApplicationError {
|
|||
'Please set the `N8N_ENCRYPTION_KEY` env var when starting the worker.',
|
||||
'See: https://docs.n8n.io/hosting/configuration/configuration-examples/encryption-key/',
|
||||
].join(' '),
|
||||
{ level: 'warning' },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { UnexpectedError } from 'n8n-workflow';
|
||||
|
||||
export class WorkflowHistoryVersionNotFoundError extends ApplicationError {}
|
||||
export class WorkflowHistoryVersionNotFoundError extends UnexpectedError {}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import type { Workflow, IWorkflowBase } from 'n8n-workflow';
|
||||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { UnexpectedError } from 'n8n-workflow';
|
||||
|
||||
export class WorkflowMissingIdError extends ApplicationError {
|
||||
export class WorkflowMissingIdError extends UnexpectedError {
|
||||
constructor(workflow: Workflow | IWorkflowBase) {
|
||||
super('Detected ID-less worklfow', { extra: { workflow } });
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { UnexpectedError } from 'n8n-workflow';
|
||||
|
||||
export type TestCaseExecutionErrorCode =
|
||||
| 'MOCKED_NODE_DOES_NOT_EXIST'
|
||||
|
@ -12,7 +12,7 @@ export type TestCaseExecutionErrorCode =
|
|||
| 'PAYLOAD_LIMIT_EXCEEDED'
|
||||
| 'UNKNOWN_ERROR';
|
||||
|
||||
export class TestCaseExecutionError extends ApplicationError {
|
||||
export class TestCaseExecutionError extends UnexpectedError {
|
||||
readonly code: TestCaseExecutionErrorCode;
|
||||
|
||||
constructor(code: TestCaseExecutionErrorCode, extra: Record<string, unknown> = {}) {
|
||||
|
@ -28,7 +28,7 @@ export type TestRunErrorCode =
|
|||
| 'INTERRUPTED'
|
||||
| 'UNKNOWN_ERROR';
|
||||
|
||||
export class TestRunError extends ApplicationError {
|
||||
export class TestRunError extends UnexpectedError {
|
||||
readonly code: TestRunErrorCode;
|
||||
|
||||
constructor(code: TestRunErrorCode, extra: Record<string, unknown> = {}) {
|
||||
|
|
|
@ -12,8 +12,9 @@ import type {
|
|||
IWorkflowExecutionDataProcess,
|
||||
} from 'n8n-workflow';
|
||||
import {
|
||||
ApplicationError,
|
||||
ExecutionStatusList,
|
||||
UnexpectedError,
|
||||
UserError,
|
||||
Workflow,
|
||||
WorkflowOperationError,
|
||||
} from 'n8n-workflow';
|
||||
|
@ -146,7 +147,7 @@ export class ExecutionService {
|
|||
if (!execution.data.executionData) throw new AbortedExecutionRetryError();
|
||||
|
||||
if (execution.finished) {
|
||||
throw new ApplicationError('The execution succeeded, so it cannot be retried.');
|
||||
throw new UnexpectedError('The execution succeeded, so it cannot be retried.');
|
||||
}
|
||||
|
||||
const executionMode = 'retry';
|
||||
|
@ -188,7 +189,7 @@ export class ExecutionService {
|
|||
})) as IWorkflowBase;
|
||||
|
||||
if (workflowData === undefined) {
|
||||
throw new ApplicationError(
|
||||
throw new UserError(
|
||||
'Workflow could not be found and so the data not be loaded for the retry.',
|
||||
{ extra: { workflowId } },
|
||||
);
|
||||
|
@ -232,7 +233,7 @@ export class ExecutionService {
|
|||
const executionData = await this.activeExecutions.getPostExecutePromise(retriedExecutionId);
|
||||
|
||||
if (!executionData) {
|
||||
throw new ApplicationError('The retry did not start for an unknown reason.');
|
||||
throw new UnexpectedError('The retry did not start for an unknown reason.');
|
||||
}
|
||||
|
||||
return !!executionData.finished;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import type { NextFunction, Response } from 'express';
|
||||
import { validate } from 'jsonschema';
|
||||
import type { JsonObject } from 'n8n-workflow';
|
||||
import { ApplicationError, jsonParse } from 'n8n-workflow';
|
||||
import { jsonParse, UnexpectedError } from 'n8n-workflow';
|
||||
|
||||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
import * as ResponseHelper from '@/response-helper';
|
||||
|
@ -44,7 +44,7 @@ export const parseRangeQuery = (
|
|||
|
||||
if (jsonFilter.waitTill) jsonFilter.waitTill = Boolean(jsonFilter.waitTill);
|
||||
|
||||
if (!isValid(jsonFilter)) throw new ApplicationError('Query does not match schema');
|
||||
if (!isValid(jsonFilter)) throw new UnexpectedError('Query does not match schema');
|
||||
|
||||
req.rangeQuery = { ...req.rangeQuery, ...jsonFilter };
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import { GlobalConfig } from '@n8n/config';
|
|||
import { Service } from '@n8n/di';
|
||||
import { ErrorReporter, Logger } from 'n8n-core';
|
||||
import type { IRun, IWorkflowBase, Workflow, WorkflowExecuteMode } from 'n8n-workflow';
|
||||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { UnexpectedError } from 'n8n-workflow';
|
||||
import type clientOAuth1 from 'oauth-1.0a';
|
||||
|
||||
import type { AbstractServer } from '@/abstract-server';
|
||||
|
@ -125,7 +125,7 @@ export class ExternalHooks {
|
|||
} catch (e) {
|
||||
const error = e instanceof Error ? e : new Error(`${e}`);
|
||||
|
||||
throw new ApplicationError('Problem loading external hook file', {
|
||||
throw new UnexpectedError('Problem loading external hook file', {
|
||||
extra: { errorMessage: error.message, hookFilePath },
|
||||
cause: error,
|
||||
});
|
||||
|
@ -160,7 +160,7 @@ export class ExternalHooks {
|
|||
} catch (cause) {
|
||||
this.logger.error(`There was a problem running hook "${hookName}"`);
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
const error = new ApplicationError(`External hook "${hookName}" failed`, { cause });
|
||||
const error = new UnexpectedError(`External hook "${hookName}" failed`, { cause });
|
||||
this.errorReporter.error(error, { level: 'fatal' });
|
||||
|
||||
// Throw original error, so that hooks control the error returned to use
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { Service } from '@n8n/di';
|
||||
import { Cipher, Logger } from 'n8n-core';
|
||||
import { jsonParse, type IDataObject, ApplicationError, ensureError } from 'n8n-workflow';
|
||||
import { jsonParse, type IDataObject, ensureError, UnexpectedError } from 'n8n-workflow';
|
||||
|
||||
import { SettingsRepository } from '@/databases/repositories/settings.repository';
|
||||
import { EventService } from '@/events/event.service';
|
||||
|
@ -95,7 +95,7 @@ export class ExternalSecretsManager {
|
|||
try {
|
||||
return jsonParse(decryptedData);
|
||||
} catch (e) {
|
||||
throw new ApplicationError(
|
||||
throw new UnexpectedError(
|
||||
'External Secrets Settings could not be decrypted. The likely reason is that a different "encryptionKey" was used to encrypt the data.',
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import InfisicalClient from 'infisical-node';
|
||||
import { getServiceTokenData } from 'infisical-node/lib/api/serviceTokenData';
|
||||
import { populateClientWorkspaceConfigsHelper } from 'infisical-node/lib/helpers/key';
|
||||
import { ApplicationError, type IDataObject, type INodeProperties } from 'n8n-workflow';
|
||||
import { UnexpectedError, type IDataObject, type INodeProperties } from 'n8n-workflow';
|
||||
|
||||
import type { SecretsProvider, SecretsProviderSettings, SecretsProviderState } from '@/interfaces';
|
||||
|
||||
|
@ -77,10 +77,10 @@ export class InfisicalProvider implements SecretsProvider {
|
|||
|
||||
async update(): Promise<void> {
|
||||
if (!this.client) {
|
||||
throw new ApplicationError('Updated attempted on Infisical when initialization failed');
|
||||
throw new UnexpectedError('Updated attempted on Infisical when initialization failed');
|
||||
}
|
||||
if (!(await this.test())[0]) {
|
||||
throw new ApplicationError('Infisical provider test failed during update');
|
||||
throw new UnexpectedError('Infisical provider test failed during update');
|
||||
}
|
||||
const secrets = (await this.client.getAllSecrets({
|
||||
environment: this.environment,
|
||||
|
@ -123,7 +123,7 @@ export class InfisicalProvider implements SecretsProvider {
|
|||
if (serviceTokenData.scopes) {
|
||||
return serviceTokenData.scopes[0].environment;
|
||||
}
|
||||
throw new ApplicationError("Couldn't find environment for Infisical");
|
||||
throw new UnexpectedError("Couldn't find environment for Infisical");
|
||||
}
|
||||
|
||||
async test(): Promise<[boolean] | [boolean, string]> {
|
||||
|
|
|
@ -4,7 +4,7 @@ import { QueryFailedError } from '@n8n/typeorm';
|
|||
import type { Entry as LdapUser, ClientOptions } from 'ldapts';
|
||||
import { Client } from 'ldapts';
|
||||
import { Cipher, Logger } from 'n8n-core';
|
||||
import { ApplicationError, jsonParse } from 'n8n-workflow';
|
||||
import { jsonParse, UnexpectedError } from 'n8n-workflow';
|
||||
import type { ConnectionOptions } from 'tls';
|
||||
|
||||
import config from '@/config';
|
||||
|
@ -89,7 +89,7 @@ export class LdapService {
|
|||
const { valid, message } = validateLdapConfigurationSchema(ldapConfig);
|
||||
|
||||
if (!valid) {
|
||||
throw new ApplicationError(message);
|
||||
throw new UnexpectedError(message);
|
||||
}
|
||||
|
||||
if (ldapConfig.loginEnabled && getCurrentAuthenticationMethod() === 'saml') {
|
||||
|
@ -165,7 +165,7 @@ export class LdapService {
|
|||
*/
|
||||
private async getClient() {
|
||||
if (this.config === undefined) {
|
||||
throw new ApplicationError('Service cannot be used without setting the property config');
|
||||
throw new UnexpectedError('Service cannot be used without setting the property config');
|
||||
}
|
||||
if (this.client === undefined) {
|
||||
const url = formatUrl(
|
||||
|
@ -304,7 +304,7 @@ export class LdapService {
|
|||
/** Schedule a synchronization job based on the interval set in the LDAP config */
|
||||
private scheduleSync(): void {
|
||||
if (!this.config.synchronizationInterval) {
|
||||
throw new ApplicationError('Interval variable has to be defined');
|
||||
throw new UnexpectedError('Interval variable has to be defined');
|
||||
}
|
||||
this.syncTimer = setInterval(async () => {
|
||||
await this.runSync('live');
|
||||
|
|
|
@ -26,7 +26,7 @@ import type {
|
|||
IVersionedNodeType,
|
||||
INodeProperties,
|
||||
} from 'n8n-workflow';
|
||||
import { ApplicationError, NodeConnectionType } from 'n8n-workflow';
|
||||
import { NodeConnectionType, UnexpectedError, UserError } from 'n8n-workflow';
|
||||
import path from 'path';
|
||||
import picocolors from 'picocolors';
|
||||
|
||||
|
@ -71,7 +71,7 @@ export class LoadNodesAndCredentials {
|
|||
) {}
|
||||
|
||||
async init() {
|
||||
if (inTest) throw new ApplicationError('Not available in tests');
|
||||
if (inTest) throw new UnexpectedError('Not available in tests');
|
||||
|
||||
// Make sure the imported modules can resolve dependencies fine.
|
||||
const delimiter = process.platform === 'win32' ? ';' : ':';
|
||||
|
@ -293,7 +293,7 @@ export class LoadNodesAndCredentials {
|
|||
) {
|
||||
const loader = new constructor(dir, this.excludeNodes, this.includeNodes);
|
||||
if (loader instanceof PackageDirectoryLoader && loader.packageName in this.loaders) {
|
||||
throw new ApplicationError(
|
||||
throw new UserError(
|
||||
picocolors.red(
|
||||
`nodes package ${loader.packageName} is already loaded.\n Please delete this second copy at path ${dir}`,
|
||||
),
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import { plainToInstance, instanceToPlain } from 'class-transformer';
|
||||
import { validate } from 'class-validator';
|
||||
import { isObjectLiteral } from 'n8n-core';
|
||||
import { ApplicationError, jsonParse } from 'n8n-workflow';
|
||||
import { jsonParse, UnexpectedError } from 'n8n-workflow';
|
||||
|
||||
export class BaseFilter {
|
||||
protected static async toFilter(rawFilter: string, Filter: typeof BaseFilter) {
|
||||
const dto = jsonParse(rawFilter, { errorMessage: 'Failed to parse filter JSON' });
|
||||
|
||||
if (!isObjectLiteral(dto)) throw new ApplicationError('Filter must be an object literal');
|
||||
if (!isObjectLiteral(dto)) throw new UnexpectedError('Filter must be an object literal');
|
||||
|
||||
const instance = plainToInstance(Filter, dto, {
|
||||
excludeExtraneousValues: true, // remove fields not in class
|
||||
|
@ -23,6 +23,6 @@ export class BaseFilter {
|
|||
private async validate() {
|
||||
const result = await validate(this);
|
||||
|
||||
if (result.length > 0) throw new ApplicationError('Parsed filter does not fit the schema');
|
||||
if (result.length > 0) throw new UnexpectedError('Parsed filter does not fit the schema');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { ApplicationError, jsonParse } from 'n8n-workflow';
|
||||
import { jsonParse, UnexpectedError } from 'n8n-workflow';
|
||||
|
||||
import { isStringArray } from '@/utils';
|
||||
|
||||
|
@ -8,7 +8,7 @@ export class BaseSelect {
|
|||
protected static toSelect(rawFilter: string, Select: typeof BaseSelect) {
|
||||
const dto = jsonParse(rawFilter, { errorMessage: 'Failed to parse filter JSON' });
|
||||
|
||||
if (!isStringArray(dto)) throw new ApplicationError('Parsed select is not a string array');
|
||||
if (!isStringArray(dto)) throw new UnexpectedError('Parsed select is not a string array');
|
||||
|
||||
return dto.reduce<Record<string, true>>((acc, field) => {
|
||||
if (!Select.selectableFields.has(field)) return acc;
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { UnexpectedError } from 'n8n-workflow';
|
||||
|
||||
import { isIntegerString } from '@/utils';
|
||||
|
||||
export class Pagination {
|
||||
static fromString(rawTake: string, rawSkip: string) {
|
||||
if (!isIntegerString(rawTake)) {
|
||||
throw new ApplicationError('Parameter take is not an integer string');
|
||||
throw new UnexpectedError('Parameter take is not an integer string');
|
||||
}
|
||||
|
||||
if (!isIntegerString(rawSkip)) {
|
||||
throw new ApplicationError('Parameter skip is not an integer string');
|
||||
throw new UnexpectedError('Parameter skip is not an integer string');
|
||||
}
|
||||
|
||||
const [take, skip] = [rawTake, rawSkip].map((o) => parseInt(o, 10));
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import type { RequestHandler } from 'express';
|
||||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { UnexpectedError } from 'n8n-workflow';
|
||||
|
||||
import type { ListQuery } from '@/requests';
|
||||
import * as ResponseHelper from '@/response-helper';
|
||||
|
@ -16,7 +16,7 @@ export const paginationListQueryMiddleware: RequestHandler = (
|
|||
|
||||
try {
|
||||
if (!rawTake && req.query.skip) {
|
||||
throw new ApplicationError('Please specify `take` when using `skip`');
|
||||
throw new UnexpectedError('Please specify `take` when using `skip`');
|
||||
}
|
||||
|
||||
if (!rawTake) return next();
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { plainToInstance } from 'class-transformer';
|
||||
import { validateSync } from 'class-validator';
|
||||
import type { RequestHandler } from 'express';
|
||||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { UnexpectedError } from 'n8n-workflow';
|
||||
|
||||
import type { ListQuery } from '@/requests';
|
||||
import * as ResponseHelper from '@/response-helper';
|
||||
|
@ -27,7 +27,7 @@ export const sortByQueryMiddleware: RequestHandler = (req: ListQuery.Request, re
|
|||
|
||||
if (validationResponse.length) {
|
||||
const validationError = validationResponse[0];
|
||||
throw new ApplicationError(validationError.constraints?.workflowSortBy ?? '');
|
||||
throw new UnexpectedError(validationError.constraints?.workflowSortBy ?? '');
|
||||
}
|
||||
|
||||
req.listQueryOptions = { ...req.listQueryOptions, sortBy };
|
||||
|
|
|
@ -6,7 +6,7 @@ import { readdir } from 'fs/promises';
|
|||
import { RoutingNode } from 'n8n-core';
|
||||
import type { ExecuteContext } from 'n8n-core';
|
||||
import type { INodeType, INodeTypeDescription, INodeTypes, IVersionedNodeType } from 'n8n-workflow';
|
||||
import { ApplicationError, NodeHelpers } from 'n8n-workflow';
|
||||
import { NodeHelpers, UnexpectedError, UserError } from 'n8n-workflow';
|
||||
import { join, dirname } from 'path';
|
||||
|
||||
import { LoadNodesAndCredentials } from './load-nodes-and-credentials';
|
||||
|
@ -52,7 +52,7 @@ export class NodeTypes implements INodeTypes {
|
|||
const node = this.loadNodesAndCredentials.getNode(nodeType);
|
||||
const versionedNodeType = NodeHelpers.getVersionedNodeType(node.type, version);
|
||||
if (toolRequested && typeof versionedNodeType.supplyData === 'function') {
|
||||
throw new ApplicationError('Node already has a `supplyData` method', { extra: { nodeType } });
|
||||
throw new UnexpectedError('Node already has a `supplyData` method', { extra: { nodeType } });
|
||||
}
|
||||
|
||||
if (
|
||||
|
@ -72,7 +72,7 @@ export class NodeTypes implements INodeTypes {
|
|||
if (!toolRequested) return versionedNodeType;
|
||||
|
||||
if (!versionedNodeType.description.usableAsTool)
|
||||
throw new ApplicationError('Node cannot be used as a tool', { extra: { nodeType } });
|
||||
throw new UserError('Node cannot be used as a tool', { extra: { nodeType } });
|
||||
|
||||
const { loadedNodes } = this.loadNodesAndCredentials;
|
||||
if (origType in loadedNodes) {
|
||||
|
|
|
@ -2,7 +2,7 @@ import { Container } from '@n8n/di';
|
|||
import type { Scope } from '@n8n/permissions';
|
||||
// eslint-disable-next-line n8n-local-rules/misplaced-n8n-typeorm-import
|
||||
import { In } from '@n8n/typeorm';
|
||||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { UnexpectedError } from 'n8n-workflow';
|
||||
|
||||
import type { User } from '@/databases/entities/user';
|
||||
import { ProjectRepository } from '@/databases/repositories/project.repository';
|
||||
|
@ -71,7 +71,7 @@ export async function userHasScopes(
|
|||
|
||||
if (projectId) return userProjectIds.includes(projectId);
|
||||
|
||||
throw new ApplicationError(
|
||||
throw new UnexpectedError(
|
||||
"`@ProjectScope` decorator was used but does not have a `credentialId`, `workflowId`, or `projectId` in its URL parameters. This is likely an implementation error. If you're a developer, please check your URL is correct or that this should be using `@GlobalScope`.",
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { heartbeatMessageSchema } from '@n8n/api-types';
|
||||
import { Service } from '@n8n/di';
|
||||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { UnexpectedError } from 'n8n-workflow';
|
||||
import type WebSocket from 'ws';
|
||||
|
||||
import type { User } from '@/databases/entities/user';
|
||||
|
@ -34,7 +34,7 @@ export class WebSocketPush extends AbstractPush<WebSocket> {
|
|||
this.onMessageReceived(pushRef, msg);
|
||||
} catch (error) {
|
||||
this.errorReporter.error(
|
||||
new ApplicationError('Error parsing push message', {
|
||||
new UnexpectedError('Error parsing push message', {
|
||||
extra: {
|
||||
userId,
|
||||
data,
|
||||
|
|
|
@ -13,7 +13,7 @@ import type {
|
|||
IRun,
|
||||
IWorkflowExecutionDataProcess,
|
||||
} from 'n8n-workflow';
|
||||
import { BINARY_ENCODING, ApplicationError, Workflow } from 'n8n-workflow';
|
||||
import { BINARY_ENCODING, Workflow, UnexpectedError } from 'n8n-workflow';
|
||||
import type PCancelable from 'p-cancelable';
|
||||
|
||||
import config from '@/config';
|
||||
|
@ -61,9 +61,8 @@ export class JobProcessor {
|
|||
});
|
||||
|
||||
if (!execution) {
|
||||
throw new ApplicationError(
|
||||
throw new UnexpectedError(
|
||||
`Worker failed to find data for execution ${executionId} (job ${job.id})`,
|
||||
{ level: 'warning' },
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -92,9 +91,8 @@ export class JobProcessor {
|
|||
});
|
||||
|
||||
if (workflowData === null) {
|
||||
throw new ApplicationError(
|
||||
throw new UnexpectedError(
|
||||
`Worker failed to find workflow ${workflowId} to run execution ${executionId} (job ${job.id})`,
|
||||
{ level: 'warning' },
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -2,12 +2,12 @@ import { GlobalConfig } from '@n8n/config';
|
|||
import { Container, Service } from '@n8n/di';
|
||||
import { ErrorReporter, InstanceSettings, isObjectLiteral, Logger } from 'n8n-core';
|
||||
import {
|
||||
ApplicationError,
|
||||
BINARY_ENCODING,
|
||||
sleep,
|
||||
jsonStringify,
|
||||
ensureError,
|
||||
ExecutionCancelledError,
|
||||
UnexpectedError,
|
||||
} from 'n8n-workflow';
|
||||
import type { IExecuteResponsePromiseData } from 'n8n-workflow';
|
||||
import assert, { strict } from 'node:assert';
|
||||
|
@ -93,7 +93,7 @@ export class ScalingService {
|
|||
void this.queue.process(JOB_TYPE_NAME, concurrency, async (job: Job) => {
|
||||
try {
|
||||
if (!this.hasValidJobData(job)) {
|
||||
throw new ApplicationError('Worker received invalid job', {
|
||||
throw new UnexpectedError('Worker received invalid job', {
|
||||
extra: { jobData: jsonStringify(job, { replaceCircularRefs: true }) },
|
||||
});
|
||||
}
|
||||
|
@ -369,13 +369,13 @@ export class ScalingService {
|
|||
private assertQueue() {
|
||||
if (this.queue) return;
|
||||
|
||||
throw new ApplicationError('This method must be called after `setupQueue`');
|
||||
throw new UnexpectedError('This method must be called after `setupQueue`');
|
||||
}
|
||||
|
||||
private assertWorker() {
|
||||
if (this.instanceSettings.instanceType === 'worker') return;
|
||||
|
||||
throw new ApplicationError('This method must be called on a `worker` instance');
|
||||
throw new UnexpectedError('This method must be called on a `worker` instance');
|
||||
}
|
||||
|
||||
// #region Queue metrics
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { GlobalConfig } from '@n8n/config';
|
||||
import { Container, Service } from '@n8n/di';
|
||||
import { caching } from 'cache-manager';
|
||||
import { ApplicationError, jsonStringify } from 'n8n-workflow';
|
||||
import { jsonStringify, UserError } from 'n8n-workflow';
|
||||
|
||||
import config from '@/config';
|
||||
import { Time } from '@/constants';
|
||||
|
@ -155,9 +155,7 @@ export class CacheService extends TypedEmitter<CacheEvents> {
|
|||
if (!key?.length) return;
|
||||
|
||||
if (this.cache.kind === 'memory') {
|
||||
throw new ApplicationError('Method `expire` not yet implemented for in-memory cache', {
|
||||
level: 'warning',
|
||||
});
|
||||
throw new UserError('Method `expire` not yet implemented for in-memory cache');
|
||||
}
|
||||
|
||||
await this.cache.store.expire(key, ttlMs * Time.milliseconds.toSeconds);
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
import type { Cache, Store, Config } from 'cache-manager';
|
||||
import Redis from 'ioredis';
|
||||
import type { Cluster, ClusterNode, ClusterOptions, RedisOptions } from 'ioredis';
|
||||
import { ApplicationError, jsonParse } from 'n8n-workflow';
|
||||
import { jsonParse, UnexpectedError } from 'n8n-workflow';
|
||||
|
||||
export class NoCacheableError implements Error {
|
||||
name = 'NoCacheableError';
|
||||
|
@ -82,7 +82,7 @@ function builder(
|
|||
await redisCache.mset(
|
||||
args.flatMap(([key, value]) => {
|
||||
if (!isCacheable(value))
|
||||
throw new ApplicationError(`"${getVal(value)}" is not a cacheable value`);
|
||||
throw new UnexpectedError(`"${getVal(value)}" is not a cacheable value`);
|
||||
return [key, getVal(value)] as [string, string];
|
||||
}),
|
||||
);
|
||||
|
|
|
@ -5,7 +5,7 @@ import { exec } from 'child_process';
|
|||
import { access as fsAccess, mkdir as fsMkdir } from 'fs/promises';
|
||||
import type { PackageDirectoryLoader } from 'n8n-core';
|
||||
import { InstanceSettings, Logger } from 'n8n-core';
|
||||
import { ApplicationError, type PublicInstalledPackage } from 'n8n-workflow';
|
||||
import { UnexpectedError, UserError, type PublicInstalledPackage } from 'n8n-workflow';
|
||||
import { promisify } from 'util';
|
||||
|
||||
import {
|
||||
|
@ -102,10 +102,10 @@ export class CommunityPackagesService {
|
|||
}
|
||||
|
||||
parseNpmPackageName(rawString?: string): CommunityPackages.ParsedPackageName {
|
||||
if (!rawString) throw new ApplicationError(PACKAGE_NAME_NOT_PROVIDED);
|
||||
if (!rawString) throw new UnexpectedError(PACKAGE_NAME_NOT_PROVIDED);
|
||||
|
||||
if (INVALID_OR_SUSPICIOUS_PACKAGE_NAME.test(rawString)) {
|
||||
throw new ApplicationError('Package name must be a single word');
|
||||
throw new UnexpectedError('Package name must be a single word');
|
||||
}
|
||||
|
||||
const scope = rawString.includes('/') ? rawString.split('/')[0] : undefined;
|
||||
|
@ -113,7 +113,7 @@ export class CommunityPackagesService {
|
|||
const packageNameWithoutScope = scope ? rawString.replace(`${scope}/`, '') : rawString;
|
||||
|
||||
if (!packageNameWithoutScope.startsWith(NODE_PACKAGE_PREFIX)) {
|
||||
throw new ApplicationError(`Package name must start with ${NODE_PACKAGE_PREFIX}`);
|
||||
throw new UnexpectedError(`Package name must start with ${NODE_PACKAGE_PREFIX}`);
|
||||
}
|
||||
|
||||
const version = packageNameWithoutScope.includes('@')
|
||||
|
@ -164,12 +164,12 @@ export class CommunityPackagesService {
|
|||
};
|
||||
|
||||
Object.entries(map).forEach(([npmMessage, n8nMessage]) => {
|
||||
if (errorMessage.includes(npmMessage)) throw new ApplicationError(n8nMessage);
|
||||
if (errorMessage.includes(npmMessage)) throw new UnexpectedError(n8nMessage);
|
||||
});
|
||||
|
||||
this.logger.warn('npm command failed', { errorMessage });
|
||||
|
||||
throw new ApplicationError(PACKAGE_FAILED_TO_INSTALL);
|
||||
throw new UnexpectedError(PACKAGE_FAILED_TO_INSTALL);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -346,7 +346,7 @@ export class CommunityPackagesService {
|
|||
await this.executeNpmCommand(command);
|
||||
} catch (error) {
|
||||
if (error instanceof Error && error.message === RESPONSE_ERROR_MESSAGES.PACKAGE_NOT_FOUND) {
|
||||
throw new ApplicationError('npm package not found', { extra: { packageName } });
|
||||
throw new UserError('npm package not found', { extra: { packageName } });
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
|
@ -360,7 +360,7 @@ export class CommunityPackagesService {
|
|||
try {
|
||||
await this.executeNpmCommand(`npm remove ${packageName}`);
|
||||
} catch {}
|
||||
throw new ApplicationError(RESPONSE_ERROR_MESSAGES.PACKAGE_LOADING_FAILED, { cause: error });
|
||||
throw new UnexpectedError(RESPONSE_ERROR_MESSAGES.PACKAGE_LOADING_FAILED, { cause: error });
|
||||
}
|
||||
|
||||
if (loader.loadedNodes.length > 0) {
|
||||
|
@ -378,7 +378,7 @@ export class CommunityPackagesService {
|
|||
this.logger.info(`Community package installed: ${packageName}`);
|
||||
return installedPackage;
|
||||
} catch (error) {
|
||||
throw new ApplicationError('Failed to save installed package', {
|
||||
throw new UnexpectedError('Failed to save installed package', {
|
||||
extra: { packageName },
|
||||
cause: error,
|
||||
});
|
||||
|
@ -388,7 +388,7 @@ export class CommunityPackagesService {
|
|||
try {
|
||||
await this.executeNpmCommand(`npm remove ${packageName}`);
|
||||
} catch {}
|
||||
throw new ApplicationError(RESPONSE_ERROR_MESSAGES.PACKAGE_DOES_NOT_CONTAIN_NODES);
|
||||
throw new UnexpectedError(RESPONSE_ERROR_MESSAGES.PACKAGE_DOES_NOT_CONTAIN_NODES);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ import type {
|
|||
IDataObject,
|
||||
IExecuteData,
|
||||
} from 'n8n-workflow';
|
||||
import { VersionedNodeType, NodeHelpers, Workflow, ApplicationError } from 'n8n-workflow';
|
||||
import { VersionedNodeType, NodeHelpers, Workflow, UnexpectedError } from 'n8n-workflow';
|
||||
|
||||
import { CredentialTypes } from '@/credential-types';
|
||||
import type { User } from '@/databases/entities/user';
|
||||
|
@ -62,7 +62,7 @@ const mockNodeTypes: INodeTypes = {
|
|||
},
|
||||
getByNameAndVersion(nodeType: string, version?: number): INodeType {
|
||||
if (!mockNodesData[nodeType]) {
|
||||
throw new ApplicationError(RESPONSE_ERROR_MESSAGES.NO_NODE, {
|
||||
throw new UnexpectedError(RESPONSE_ERROR_MESSAGES.NO_NODE, {
|
||||
tags: { nodeType },
|
||||
});
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ import type {
|
|||
ILocalLoadOptionsFunctions,
|
||||
IExecuteData,
|
||||
} from 'n8n-workflow';
|
||||
import { Workflow, ApplicationError } from 'n8n-workflow';
|
||||
import { Workflow, UnexpectedError } from 'n8n-workflow';
|
||||
|
||||
import { NodeTypes } from '@/node-types';
|
||||
|
||||
|
@ -91,7 +91,7 @@ export class DynamicNodeParametersService {
|
|||
// requiring a baseURL to be defined can at least not a random server be called.
|
||||
// In the future this code has to get improved that it does not use the request information from
|
||||
// the request rather resolves it via the parameter-path and nodeType data.
|
||||
throw new ApplicationError(
|
||||
throw new UnexpectedError(
|
||||
'Node type does not exist or does not have "requestDefaults.baseURL" defined!',
|
||||
{ tags: { nodeType: nodeType.description.name } },
|
||||
);
|
||||
|
@ -152,7 +152,7 @@ export class DynamicNodeParametersService {
|
|||
}
|
||||
|
||||
if (!Array.isArray(optionsData)) {
|
||||
throw new ApplicationError('The returned data is not an array');
|
||||
throw new UnexpectedError('The returned data is not an array');
|
||||
}
|
||||
|
||||
return optionsData[0].map((item) => item.json) as unknown as INodePropertyOptions[];
|
||||
|
@ -258,7 +258,7 @@ export class DynamicNodeParametersService {
|
|||
): NodeMethod {
|
||||
const method = nodeType.methods?.[type]?.[methodName] as NodeMethod;
|
||||
if (typeof method !== 'function') {
|
||||
throw new ApplicationError('Node type does not have method defined', {
|
||||
throw new UnexpectedError('Node type does not have method defined', {
|
||||
tags: { nodeType: nodeType.description.name },
|
||||
extra: { methodName },
|
||||
});
|
||||
|
|
|
@ -5,7 +5,7 @@ import { type Scope } from '@n8n/permissions';
|
|||
import type { FindOptionsWhere, EntityManager } from '@n8n/typeorm';
|
||||
// eslint-disable-next-line n8n-local-rules/misplaced-n8n-typeorm-import
|
||||
import { In, Not } from '@n8n/typeorm';
|
||||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { UserError } from 'n8n-workflow';
|
||||
|
||||
import { UNLIMITED_LICENSE_QUOTA } from '@/constants';
|
||||
import { Project } from '@/databases/entities/project';
|
||||
|
@ -23,7 +23,7 @@ import { License } from '@/license';
|
|||
import { CacheService } from './cache/cache.service';
|
||||
import { RoleService } from './role.service';
|
||||
|
||||
export class TeamProjectOverQuotaError extends ApplicationError {
|
||||
export class TeamProjectOverQuotaError extends UserError {
|
||||
constructor(limit: number) {
|
||||
super(
|
||||
`Attempted to create a new project but quota is already exhausted. You may have a maximum of ${limit} team projects.`,
|
||||
|
@ -31,7 +31,7 @@ export class TeamProjectOverQuotaError extends ApplicationError {
|
|||
}
|
||||
}
|
||||
|
||||
export class UnlicensedProjectRoleError extends ApplicationError {
|
||||
export class UnlicensedProjectRoleError extends UserError {
|
||||
constructor(role: ProjectRole) {
|
||||
super(`Your instance is not licensed to use role "${role}".`);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import type { ProjectRole } from '@n8n/api-types';
|
||||
import { Service } from '@n8n/di';
|
||||
import { combineScopes, type Resource, type Scope } from '@n8n/permissions';
|
||||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { UnexpectedError } from 'n8n-workflow';
|
||||
|
||||
import type { CredentialsEntity } from '@/databases/entities/credentials-entity';
|
||||
import type { ProjectRelation } from '@/databases/entities/project-relation';
|
||||
|
@ -199,7 +199,7 @@ export class RoleService {
|
|||
}
|
||||
|
||||
if (!('active' in entity) && !('type' in entity)) {
|
||||
throw new ApplicationError('Cannot detect if entity is a workflow or credential.');
|
||||
throw new UnexpectedError('Cannot detect if entity is a workflow or credential.');
|
||||
}
|
||||
|
||||
entity.scopes = this.combineResourceScopes(
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { Service } from '@n8n/di';
|
||||
import { Logger } from 'n8n-core';
|
||||
import type { IUserSettings } from 'n8n-workflow';
|
||||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { UnexpectedError } from 'n8n-workflow';
|
||||
|
||||
import type { User, AssignableRole } from '@/databases/entities/user';
|
||||
import { UserRepository } from '@/databases/repositories/user.repository';
|
||||
|
@ -68,7 +68,7 @@ export class UserService {
|
|||
};
|
||||
|
||||
if (options?.withInviteUrl && !options?.inviterId) {
|
||||
throw new ApplicationError('Inviter ID is required to generate invite URL');
|
||||
throw new UnexpectedError('Inviter ID is required to generate invite URL');
|
||||
}
|
||||
|
||||
if (options?.withInviteUrl && options?.inviterId && publicUser.isPending) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { Service } from '@n8n/di';
|
||||
import { ApplicationError, type IWorkflowBase, type IWorkflowLoader } from 'n8n-workflow';
|
||||
import { UnexpectedError, type IWorkflowBase, type IWorkflowLoader } from 'n8n-workflow';
|
||||
|
||||
import { WorkflowRepository } from '@/databases/repositories/workflow.repository';
|
||||
|
||||
|
@ -11,7 +11,7 @@ export class WorkflowLoaderService implements IWorkflowLoader {
|
|||
const workflow = await this.workflowRepository.findById(workflowId);
|
||||
|
||||
if (!workflow) {
|
||||
throw new ApplicationError(`Failed to find workflow with ID "${workflowId}"`);
|
||||
throw new UnexpectedError(`Failed to find workflow with ID "${workflowId}"`);
|
||||
}
|
||||
|
||||
return workflow;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { Container } from '@n8n/di';
|
||||
import { mock } from 'jest-mock-extended';
|
||||
import type { ErrorReporter } from 'n8n-core';
|
||||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { UnexpectedError } from 'n8n-workflow';
|
||||
|
||||
import type { ServiceClass } from '@/shutdown/shutdown.service';
|
||||
import { ShutdownService } from '@/shutdown/shutdown.service';
|
||||
|
@ -84,8 +84,8 @@ describe('ShutdownService', () => {
|
|||
await shutdownService.waitForShutdown();
|
||||
|
||||
expect(errorReporter.error).toHaveBeenCalledTimes(1);
|
||||
const error = errorReporter.error.mock.calls[0][0] as ApplicationError;
|
||||
expect(error).toBeInstanceOf(ApplicationError);
|
||||
const error = errorReporter.error.mock.calls[0][0] as UnexpectedError;
|
||||
expect(error).toBeInstanceOf(UnexpectedError);
|
||||
expect(error.message).toBe('Failed to shutdown gracefully');
|
||||
expect(error.extra).toEqual({
|
||||
component: 'MockComponent.onShutdown()',
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { Container, Service } from '@n8n/di';
|
||||
import { type Class, ErrorReporter } from 'n8n-core';
|
||||
import { Logger } from 'n8n-core';
|
||||
import { ApplicationError, assert } from 'n8n-workflow';
|
||||
import { assert, UnexpectedError, UserError } from 'n8n-workflow';
|
||||
|
||||
import { LOWEST_SHUTDOWN_PRIORITY, HIGHEST_SHUTDOWN_PRIORITY } from '@/constants';
|
||||
|
||||
|
@ -14,10 +14,9 @@ export interface ShutdownHandler {
|
|||
}
|
||||
|
||||
/** Error reported when a listener fails to shutdown gracefully */
|
||||
export class ComponentShutdownError extends ApplicationError {
|
||||
export class ComponentShutdownError extends UnexpectedError {
|
||||
constructor(componentName: string, cause: Error) {
|
||||
super('Failed to shutdown gracefully', {
|
||||
level: 'error',
|
||||
cause,
|
||||
extra: { component: componentName },
|
||||
});
|
||||
|
@ -39,7 +38,7 @@ export class ShutdownService {
|
|||
/** Registers given listener to be notified when the application is shutting down */
|
||||
register(priority: number, handler: ShutdownHandler) {
|
||||
if (priority < LOWEST_SHUTDOWN_PRIORITY || priority > HIGHEST_SHUTDOWN_PRIORITY) {
|
||||
throw new ApplicationError(
|
||||
throw new UserError(
|
||||
`Invalid shutdown priority. Please set it between ${LOWEST_SHUTDOWN_PRIORITY} and ${HIGHEST_SHUTDOWN_PRIORITY}.`,
|
||||
{ extra: { priority } },
|
||||
);
|
||||
|
@ -57,14 +56,14 @@ export class ShutdownService {
|
|||
|
||||
for (const { serviceClass, methodName } of handlers) {
|
||||
if (!Container.has(serviceClass)) {
|
||||
throw new ApplicationError(
|
||||
throw new UserError(
|
||||
`Component "${serviceClass.name}" is not registered with the DI container. Any component using @OnShutdown() must be decorated with @Service()`,
|
||||
);
|
||||
}
|
||||
|
||||
const service = Container.get(serviceClass);
|
||||
if (!service[methodName]) {
|
||||
throw new ApplicationError(
|
||||
throw new UserError(
|
||||
`Component "${serviceClass.name}" does not have a "${methodName}" method`,
|
||||
);
|
||||
}
|
||||
|
@ -74,7 +73,7 @@ export class ShutdownService {
|
|||
/** Signals all registered listeners that the application is shutting down */
|
||||
shutdown() {
|
||||
if (this.shutdownPromise) {
|
||||
throw new ApplicationError('App is already shutting down');
|
||||
throw new UnexpectedError('App is already shutting down');
|
||||
}
|
||||
|
||||
this.shutdownPromise = this.startShutdown();
|
||||
|
@ -83,7 +82,7 @@ export class ShutdownService {
|
|||
/** Returns a promise that resolves when all the registered listeners have shut down */
|
||||
async waitForShutdown(): Promise<void> {
|
||||
if (!this.shutdownPromise) {
|
||||
throw new ApplicationError('App is not shutting down');
|
||||
throw new UnexpectedError('App is not shutting down');
|
||||
}
|
||||
|
||||
await this.shutdownPromise;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { UserError } from 'n8n-workflow';
|
||||
|
||||
export class InvalidSamlMetadataError extends ApplicationError {
|
||||
export class InvalidSamlMetadataError extends UserError {
|
||||
constructor() {
|
||||
super('Invalid SAML metadata', { level: 'warning' });
|
||||
super('Invalid SAML metadata');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import axios from 'axios';
|
|||
import type express from 'express';
|
||||
import https from 'https';
|
||||
import { Logger } from 'n8n-core';
|
||||
import { ApplicationError, jsonParse } from 'n8n-workflow';
|
||||
import { jsonParse, UnexpectedError } from 'n8n-workflow';
|
||||
import type { IdentityProviderInstance, ServiceProviderInstance } from 'samlify';
|
||||
import type { BindingContext, PostBindingContext } from 'samlify/types/src/entity';
|
||||
|
||||
|
@ -124,7 +124,7 @@ export class SamlService {
|
|||
|
||||
getIdentityProviderInstance(forceRecreate = false): IdentityProviderInstance {
|
||||
if (this.samlify === undefined) {
|
||||
throw new ApplicationError('Samlify is not initialized');
|
||||
throw new UnexpectedError('Samlify is not initialized');
|
||||
}
|
||||
if (this.identityProviderInstance === undefined || forceRecreate) {
|
||||
this.identityProviderInstance = this.samlify.IdentityProvider({
|
||||
|
@ -137,7 +137,7 @@ export class SamlService {
|
|||
|
||||
getServiceProviderInstance(): ServiceProviderInstance {
|
||||
if (this.samlify === undefined) {
|
||||
throw new ApplicationError('Samlify is not initialized');
|
||||
throw new UnexpectedError('Samlify is not initialized');
|
||||
}
|
||||
return getServiceProviderInstance(this._samlPreferences, this.samlify);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import type { TaskRunner } from '@n8n/task-runner';
|
||||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { UnexpectedError } from 'n8n-workflow';
|
||||
|
||||
export class TaskRunnerDisconnectedError extends ApplicationError {
|
||||
export class TaskRunnerDisconnectedError extends UnexpectedError {
|
||||
description: string;
|
||||
|
||||
constructor(
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { UserError } from 'n8n-workflow';
|
||||
|
||||
export class TaskRunnerFailedHeartbeatError extends ApplicationError {
|
||||
export class TaskRunnerFailedHeartbeatError extends UserError {
|
||||
description: string;
|
||||
|
||||
constructor(heartbeatInterval: number, isSelfHosted: boolean) {
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { UserError } from 'n8n-workflow';
|
||||
|
||||
import type { TaskRunner } from '@/task-runners/task-broker/task-broker.service';
|
||||
|
||||
export class TaskRunnerOomError extends ApplicationError {
|
||||
export class TaskRunnerOomError extends UserError {
|
||||
description: string;
|
||||
|
||||
constructor(
|
||||
readonly runnerId: TaskRunner['id'],
|
||||
isCloudDeployment: boolean,
|
||||
) {
|
||||
super('Node ran out of memory.', { level: 'error' });
|
||||
super('Node ran out of memory');
|
||||
|
||||
const fixSuggestions = {
|
||||
reduceItems:
|
||||
|
|
|
@ -1,14 +1,12 @@
|
|||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { UnexpectedError } from 'n8n-workflow';
|
||||
|
||||
export class TaskRunnerRestartLoopError extends ApplicationError {
|
||||
export class TaskRunnerRestartLoopError extends UnexpectedError {
|
||||
constructor(
|
||||
readonly howManyTimes: number,
|
||||
readonly timePeriodMs: number,
|
||||
) {
|
||||
const message = `Task runner has restarted ${howManyTimes} times within ${timePeriodMs / 1000} seconds. This is an abnormally high restart rate that suggests a bug or other issue is preventing your runner process from starting up. If this issues persists, please file a report at: https://github.com/n8n-io/n8n/issues`;
|
||||
|
||||
super(message, {
|
||||
level: 'fatal',
|
||||
});
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { UserError } from 'n8n-workflow';
|
||||
|
||||
export class TaskDeferredError extends ApplicationError {
|
||||
export class TaskDeferredError extends UserError {
|
||||
constructor() {
|
||||
super('Task deferred until runner is ready', { level: 'info' });
|
||||
super('Task deferred until runner is ready');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { UserError } from 'n8n-workflow';
|
||||
|
||||
export class TaskRejectError extends ApplicationError {
|
||||
export class TaskRejectError extends UserError {
|
||||
constructor(public reason: string) {
|
||||
super(`Task rejected with reason: ${reason}`, { level: 'info' });
|
||||
super(`Task rejected with reason: ${reason}`);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import type { TaskRunnerMode } from '@n8n/config/src/configs/runners.config';
|
||||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { OperationalError } from 'n8n-workflow';
|
||||
|
||||
export class TaskRunnerTimeoutError extends ApplicationError {
|
||||
export class TaskRunnerTimeoutError extends OperationalError {
|
||||
description: string;
|
||||
|
||||
constructor({
|
||||
|
|
|
@ -2,7 +2,7 @@ import { TaskRunnersConfig } from '@n8n/config';
|
|||
import { Service } from '@n8n/di';
|
||||
import type { BrokerMessage, RunnerMessage } from '@n8n/task-runner';
|
||||
import { Logger } from 'n8n-core';
|
||||
import { ApplicationError, jsonStringify } from 'n8n-workflow';
|
||||
import { jsonStringify, UserError } from 'n8n-workflow';
|
||||
import type WebSocket from 'ws';
|
||||
|
||||
import { Time, WsStatusCodes } from '@/constants';
|
||||
|
@ -49,7 +49,7 @@ export class TaskBrokerWsServer {
|
|||
const { heartbeatInterval } = this.taskTunnersConfig;
|
||||
|
||||
if (heartbeatInterval <= 0) {
|
||||
throw new ApplicationError('Heartbeat interval must be greater than 0');
|
||||
throw new UserError('Heartbeat interval must be greater than 0');
|
||||
}
|
||||
|
||||
this.heartbeatTimer = setInterval(() => {
|
||||
|
|
|
@ -7,7 +7,7 @@ import type {
|
|||
TaskResultData,
|
||||
} from '@n8n/task-runner';
|
||||
import { Logger } from 'n8n-core';
|
||||
import { ApplicationError } from 'n8n-workflow';
|
||||
import { UnexpectedError, UserError } from 'n8n-workflow';
|
||||
import { nanoid } from 'nanoid';
|
||||
|
||||
import config from '@/config';
|
||||
|
@ -92,7 +92,7 @@ export class TaskBroker {
|
|||
private readonly taskRunnerLifecycleEvents: TaskRunnerLifecycleEvents,
|
||||
) {
|
||||
if (this.taskRunnersConfig.taskTimeout <= 0) {
|
||||
throw new ApplicationError('Task timeout must be greater than 0');
|
||||
throw new UserError('Task timeout must be greater than 0');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -420,17 +420,12 @@ export class TaskBroker {
|
|||
private async getRunnerOrFailTask(taskId: Task['id']): Promise<TaskRunner> {
|
||||
const task = this.tasks.get(taskId);
|
||||
if (!task) {
|
||||
throw new ApplicationError(`Cannot find runner, failed to find task (${taskId})`, {
|
||||
level: 'error',
|
||||
});
|
||||
throw new UnexpectedError(`Cannot find runner, failed to find task (${taskId})`);
|
||||
}
|
||||
const runner = this.knownRunners.get(task.runnerId);
|
||||
if (!runner) {
|
||||
const error = new ApplicationError(
|
||||
const error = new UnexpectedError(
|
||||
`Cannot find runner, failed to find runner (${task.runnerId})`,
|
||||
{
|
||||
level: 'error',
|
||||
},
|
||||
);
|
||||
await this.failTask(taskId, error);
|
||||
throw error;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue