From 940f389c6fe8cd2e12942a3ebcaa753e5497900e Mon Sep 17 00:00:00 2001 From: Bernhard Wittmann Date: Fri, 19 Jun 2026 09:19:26 +0200 Subject: [PATCH] fix(Form Trigger Node): Add default value for authentication parameter to prevent crash on old workflows (#32627) Co-authored-by: returnSGD --- .../nodes-base/nodes/Form/test/utils.test.ts | 32 +++++++++++++++++-- packages/nodes-base/nodes/Form/utils/utils.ts | 2 +- .../nodes/Webhook/test/utils.test.ts | 7 ++-- packages/nodes-base/nodes/Webhook/utils.ts | 4 +-- 4 files changed, 37 insertions(+), 8 deletions(-) diff --git a/packages/nodes-base/nodes/Form/test/utils.test.ts b/packages/nodes-base/nodes/Form/test/utils.test.ts index a3cf415d27d..55fabdef278 100644 --- a/packages/nodes-base/nodes/Form/test/utils.test.ts +++ b/packages/nodes-base/nodes/Form/test/utils.test.ts @@ -436,7 +436,7 @@ describe('FormTrigger, formWebhook', () => { .calledWith('formDescription') .mockReturnValue('Test Description'); executeFunctions.getNodeParameter.calledWith('responseMode').mockReturnValue('onReceived'); - executeFunctions.getNodeParameter.calledWith('authentication').mockReturnValue('none'); + executeFunctions.getNodeParameter.calledWith('authentication', 'none').mockReturnValue('none'); executeFunctions.getRequestObject.mockReturnValue({ method: 'GET', query: {} } as any); executeFunctions.getMode.mockReturnValue('manual'); executeFunctions.getInstanceId.mockReturnValue('instanceId'); @@ -447,6 +447,32 @@ describe('FormTrigger, formWebhook', () => { vi.clearAllMocks(); }); + it('renders the form when the node has no stored authentication parameter', async () => { + const ctx = mock(); + ctx.getNode.mockReturnValue({ typeVersion: 1, name: 'Form Trigger' } as INode); + + // Mirror the engine: getNodeParameter throws when the key is absent and + // no default is supplied, but returns the default when one is given. + ctx.getNodeParameter.calledWith('authentication').mockImplementation(() => { + throw new Error('Could not get parameter'); + }); + ctx.getNodeParameter.calledWith('authentication', 'none').mockReturnValue('none'); + + ctx.getNodeParameter.calledWith('options').mockReturnValue({}); + ctx.getNodeParameter.calledWith('formFields.values').mockReturnValue([]); + ctx.getNodeParameter.calledWith('formTitle').mockReturnValue('Test Form'); + ctx.getNodeParameter.calledWith('formDescription').mockReturnValue(''); + ctx.getNodeParameter.calledWith('responseMode').mockReturnValue('onReceived'); + + ctx.getRequestObject.mockReturnValue({ method: 'GET', query: {}, headers: {} } as any); + ctx.getResponseObject.mockReturnValue({ render: vi.fn(), setHeader: vi.fn() } as any); + ctx.getMode.mockReturnValue('manual'); + ctx.getInstanceId.mockReturnValue('instanceId'); + ctx.getChildNodes.mockReturnValue([]); + + await expect(formWebhook(ctx)).resolves.toEqual({ noWebhookResponse: true }); + }); + it('should call response render', async () => { const mockRender = vi.fn(); @@ -831,7 +857,7 @@ describe('FormTrigger, formWebhook', () => { ctx.getNodeParameter.calledWith('formTitle').mockReturnValue('Test Form'); ctx.getNodeParameter.calledWith('formDescription').mockReturnValue('Test Description'); ctx.getNodeParameter.calledWith('responseMode').mockReturnValue('onReceived'); - ctx.getNodeParameter.calledWith('authentication').mockReturnValue('n8nUserAuth'); + ctx.getNodeParameter.calledWith('authentication', 'none').mockReturnValue('n8nUserAuth'); ctx.getNodeParameter.calledWith('formFields.values').mockReturnValue(formFields); ctx.getRequestObject.mockReturnValue(request as any); ctx.getHeaderData.mockReturnValue(request.headers); @@ -879,7 +905,7 @@ describe('FormTrigger, formWebhook', () => { }; ctx.getNode.mockReturnValue({ typeVersion: 2.6 } as INode); ctx.getNodeParameter.calledWith('options').mockReturnValue({}); - ctx.getNodeParameter.calledWith('authentication').mockReturnValue('n8nUserAuth'); + ctx.getNodeParameter.calledWith('authentication', 'none').mockReturnValue('n8nUserAuth'); ctx.getRequestObject.mockReturnValue({ method: 'GET', originalUrl: '/form/test', diff --git a/packages/nodes-base/nodes/Form/utils/utils.ts b/packages/nodes-base/nodes/Form/utils/utils.ts index 2412749119a..c4d0f82acef 100644 --- a/packages/nodes-base/nodes/Form/utils/utils.ts +++ b/packages/nodes-base/nodes/Form/utils/utils.ts @@ -793,7 +793,7 @@ export async function formWebhook( return { noWebhookResponse: true }; } - const authentication = (context.getNodeParameter(authProperty) as string) ?? 'none'; + const authentication = context.getNodeParameter(authProperty, 'none') as string; let authedUser: IUser | undefined; if (node.typeVersion > 1) { if (authentication === 'n8nUserAuth') { diff --git a/packages/nodes-base/nodes/Webhook/test/utils.test.ts b/packages/nodes-base/nodes/Webhook/test/utils.test.ts index 4c71db902d0..e87dcdc0892 100644 --- a/packages/nodes-base/nodes/Webhook/test/utils.test.ts +++ b/packages/nodes-base/nodes/Webhook/test/utils.test.ts @@ -714,7 +714,7 @@ describe('Auth token generation', () => { await generateFormPostBasicAuthToken(webhookFunctions, 'authentication'); - expect(webhookFunctions.getNodeParameter).toHaveBeenCalledWith('authentication'); + expect(webhookFunctions.getNodeParameter).toHaveBeenCalledWith('authentication', 'none'); }); it('should use passed authentication key', async () => { @@ -725,7 +725,10 @@ describe('Auth token generation', () => { await generateFormPostBasicAuthToken(webhookFunctions, 'incomingAuthentication'); - expect(webhookFunctions.getNodeParameter).toHaveBeenCalledWith('incomingAuthentication'); + expect(webhookFunctions.getNodeParameter).toHaveBeenCalledWith( + 'incomingAuthentication', + 'none', + ); }); it('should handle "none" authentication', async () => { diff --git a/packages/nodes-base/nodes/Webhook/utils.ts b/packages/nodes-base/nodes/Webhook/utils.ts index 311c48483e8..2d5108afd78 100644 --- a/packages/nodes-base/nodes/Webhook/utils.ts +++ b/packages/nodes-base/nodes/Webhook/utils.ts @@ -236,7 +236,7 @@ export async function validateWebhookAuthentication( ctx: IWebhookFunctions, authPropertyName: string, ): Promise { - const authentication = ctx.getNodeParameter(authPropertyName) as string; + const authentication = ctx.getNodeParameter(authPropertyName, 'none') as string; if (authentication === 'none') return; const req = ctx.getRequestObject(); @@ -426,7 +426,7 @@ export async function generateFormPostBasicAuthToken( ) { const node = context.getNode(); - const authentication = context.getNodeParameter(authPropertyName); + const authentication = context.getNodeParameter(authPropertyName, 'none'); if (authentication === 'none') return; let credentials: ICredentialDataDecryptedObject | undefined;