diff --git a/packages/cli/src/ActiveWorkflowRunner.ts b/packages/cli/src/ActiveWorkflowRunner.ts index 66d4ec02e2..be77bd101f 100644 --- a/packages/cli/src/ActiveWorkflowRunner.ts +++ b/packages/cli/src/ActiveWorkflowRunner.ts @@ -39,6 +39,8 @@ import { LoggerProxy as Logger, } from 'n8n-workflow'; +const WEBHOOK_PROD_UNREGISTERED_HINT = `The workflow must be active for a production URL to run successfully. You can activate the workflow using the toggle in the top-right of the editor. Note that unlike test URL calls, production URL calls aren't shown on the canvas (only in the executions list)`; + export class ActiveWorkflowRunner { private activeWorkflows: ActiveWorkflows | null = null; @@ -148,7 +150,7 @@ export class ActiveWorkflowRunner { const dynamicWebhooks = await Db.collections.Webhook?.find({ webhookId, method: httpMethod, pathLength: pathElements.length }); if (dynamicWebhooks === undefined || dynamicWebhooks.length === 0) { // The requested webhook is not registered - throw new ResponseHelper.ResponseError(`The requested webhook "${httpMethod} ${path}" is not registered.`, 404, 404); + throw new ResponseHelper.ResponseError(`The requested webhook "${httpMethod} ${path}" is not registered.`, 404, 404, WEBHOOK_PROD_UNREGISTERED_HINT); } let maxMatches = 0; @@ -169,7 +171,7 @@ export class ActiveWorkflowRunner { } }); if (webhook === undefined) { - throw new ResponseHelper.ResponseError(`The requested webhook "${httpMethod} ${path}" is not registered.`, 404, 404); + throw new ResponseHelper.ResponseError(`The requested webhook "${httpMethod} ${path}" is not registered.`, 404, 404, WEBHOOK_PROD_UNREGISTERED_HINT); } path = webhook!.webhookPath; diff --git a/packages/cli/src/ResponseHelper.ts b/packages/cli/src/ResponseHelper.ts index 465fdb5dde..24a9d37b53 100644 --- a/packages/cli/src/ResponseHelper.ts +++ b/packages/cli/src/ResponseHelper.ts @@ -21,17 +21,21 @@ export class ResponseError extends Error { // The HTTP status code of response httpStatusCode?: number; - // The error code in the resonse + // The error code in the response errorCode?: number; + // The error hint the response + hint?: string; + /** * Creates an instance of ResponseError. * @param {string} message The error message * @param {number} [errorCode] The error code which can be used by frontend to identify the actual error * @param {number} [httpStatusCode] The HTTP status code the response should have + * @param {string} [hint] The error hint to provide a context (webhook related) * @memberof ResponseError */ - constructor(message: string, errorCode?: number, httpStatusCode?: number) { + constructor(message: string, errorCode?: number, httpStatusCode?: number, hint?:string) { super(message); this.name = 'ResponseError'; @@ -41,6 +45,9 @@ export class ResponseError extends Error { if (httpStatusCode) { this.httpStatusCode = httpStatusCode; } + if (hint) { + this.hint = hint; + } } } @@ -91,6 +98,7 @@ export function sendErrorResponse(res: Response, error: ResponseError) { const response = { code: 0, message: 'Unknown error', + hint: '', }; if (error.name === 'NodeApiError') { @@ -103,6 +111,9 @@ export function sendErrorResponse(res: Response, error: ResponseError) { if (error.message) { response.message = error.message; } + if (error.hint) { + response.hint = error.hint; + } if (error.stack && process.env.NODE_ENV !== 'production') { // @ts-ignore response.stack = error.stack; diff --git a/packages/cli/src/TestWebhooks.ts b/packages/cli/src/TestWebhooks.ts index b9dcf09fcb..a8aa17720f 100644 --- a/packages/cli/src/TestWebhooks.ts +++ b/packages/cli/src/TestWebhooks.ts @@ -21,7 +21,7 @@ import { WorkflowExecuteMode, } from 'n8n-workflow'; - +const WEBHOOK_TEST_UNREGISTERED_HINT = `Click the 'Execute workflow' button on the canvas, then try again. (In test mode, the webhook only works for one call after you click this button)`; export class TestWebhooks { @@ -72,7 +72,7 @@ export class TestWebhooks { webhookData = this.activeWebhooks!.get(httpMethod, pathElements.join('/'), webhookId); if (webhookData === undefined) { // The requested webhook is not registered - throw new ResponseHelper.ResponseError(`The requested webhook "${httpMethod} ${path}" is not registered.`, 404, 404); + throw new ResponseHelper.ResponseError(`The requested webhook "${httpMethod} ${path}" is not registered.`, 404, 404, WEBHOOK_TEST_UNREGISTERED_HINT); } path = webhookData.path; @@ -90,7 +90,7 @@ export class TestWebhooks { // TODO: Clean that duplication up one day and improve code generally if (this.testWebhookData[webhookKey] === undefined) { // The requested webhook is not registered - throw new ResponseHelper.ResponseError(`The requested webhook "${httpMethod} ${path}" is not registered.`, 404, 404); + throw new ResponseHelper.ResponseError(`The requested webhook "${httpMethod} ${path}" is not registered.`, 404, 404, WEBHOOK_TEST_UNREGISTERED_HINT); } const workflow = this.testWebhookData[webhookKey].workflow; @@ -145,7 +145,7 @@ export class TestWebhooks { if (webhookMethods === undefined) { // The requested webhook is not registered - throw new ResponseHelper.ResponseError(`The requested webhook "${path}" is not registered.`, 404, 404); + throw new ResponseHelper.ResponseError(`The requested webhook "${path}" is not registered.`, 404, 404, WEBHOOK_TEST_UNREGISTERED_HINT); } return webhookMethods;