diff --git a/packages/cli/src/scaling/job-processor.ts b/packages/cli/src/scaling/job-processor.ts index 768338d9b0..84657f52a0 100644 --- a/packages/cli/src/scaling/job-processor.ts +++ b/packages/cli/src/scaling/job-processor.ts @@ -1,6 +1,12 @@ import type { RunningJobSummary } from '@n8n/api-types'; import { Service } from '@n8n/di'; -import { InstanceSettings, WorkflowExecute, ErrorReporter, Logger } from 'n8n-core'; +import { + WorkflowHasIssuesError, + InstanceSettings, + WorkflowExecute, + ErrorReporter, + Logger, +} from 'n8n-core'; import type { ExecutionStatus, IExecuteResponsePromiseData, @@ -178,13 +184,33 @@ export class JobProcessor { userId: manualData?.userId, }; - workflowRun = this.manualExecutionService.runManually( - data, - workflow, - additionalData, - executionId, - resultData.pinData, - ); + try { + workflowRun = this.manualExecutionService.runManually( + data, + workflow, + additionalData, + executionId, + resultData.pinData, + ); + } catch (error) { + if (error instanceof WorkflowHasIssuesError) { + // execution did not even start, but we call `workflowExecuteAfter` to notify main + + const now = new Date(); + const runData: IRun = { + mode: 'manual', + status: 'error', + finished: false, + startedAt: now, + stoppedAt: now, + data: { resultData: { error, runData: {} } }, + }; + + await additionalData.hooks.executeHookFunctions('workflowExecuteAfter', [runData]); + return { success: false }; + } + throw error; + } } else if (execution.data !== undefined) { workflowExecute = new WorkflowExecute(additionalData, execution.mode, execution.data); workflowRun = workflowExecute.processRunExecutionData(workflow); diff --git a/packages/core/src/errors/workflow-has-issues.error.ts b/packages/core/src/errors/workflow-has-issues.error.ts new file mode 100644 index 0000000000..77f73131c2 --- /dev/null +++ b/packages/core/src/errors/workflow-has-issues.error.ts @@ -0,0 +1,7 @@ +import { WorkflowOperationError } from 'n8n-workflow'; + +export class WorkflowHasIssuesError extends WorkflowOperationError { + constructor() { + super('The workflow has issues and cannot be executed for that reason. Please fix them first.'); + } +} diff --git a/packages/core/src/execution-engine/workflow-execute.ts b/packages/core/src/execution-engine/workflow-execute.ts index 2eb7a9e7fe..233b6c3c97 100644 --- a/packages/core/src/execution-engine/workflow-execute.ts +++ b/packages/core/src/execution-engine/workflow-execute.ts @@ -44,7 +44,6 @@ import type { } from 'n8n-workflow'; import { LoggerProxy as Logger, - WorkflowOperationError, NodeHelpers, NodeConnectionType, ApplicationError, @@ -56,6 +55,7 @@ import { import PCancelable from 'p-cancelable'; import { ErrorReporter } from '@/errors/error-reporter'; +import { WorkflowHasIssuesError } from '@/errors/workflow-has-issues.error'; import * as NodeExecuteFunctions from '@/node-execute-functions'; import { ExecuteContext, PollContext } from './node-execution-context'; @@ -1246,9 +1246,7 @@ export class WorkflowExecute { pinDataNodeNames, }); if (workflowIssues !== null) { - throw new WorkflowOperationError( - 'The workflow has issues and cannot be executed for that reason. Please fix them first.', - ); + throw new WorkflowHasIssuesError(); } // Variables which hold temporary data for each node-execution diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 12aa968fcc..0a620468bf 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -12,6 +12,7 @@ export * from './instance-settings'; export * from './logging'; export * from './nodes-loader'; export * from './utils'; +export { WorkflowHasIssuesError } from './errors/workflow-has-issues.error'; export * from './interfaces'; export * from './node-execute-functions';