From 75c1a4c5b3d7debfabdee83f4dd6b1d732aa0185 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Ovejero?= Date: Tue, 6 May 2025 11:23:45 +0200 Subject: [PATCH] fix(core): Fix task runner validation error on array of arrays (#15106) --- .../__tests__/result-validation.test.ts | 8 +++++++ .../src/js-task-runner/obj-utils.ts | 2 +- .../src/js-task-runner/result-validation.ts | 22 +++++++++++++------ 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/packages/@n8n/task-runner/src/js-task-runner/__tests__/result-validation.test.ts b/packages/@n8n/task-runner/src/js-task-runner/__tests__/result-validation.test.ts index 324ff6f749..65587280c3 100644 --- a/packages/@n8n/task-runner/src/js-task-runner/__tests__/result-validation.test.ts +++ b/packages/@n8n/task-runner/src/js-task-runner/__tests__/result-validation.test.ts @@ -1,5 +1,6 @@ import { ValidationError } from '@/js-task-runner/errors/validation-error'; import { + NonArrayOfObjectsError, validateRunForAllItemsOutput, validateRunForEachItemOutput, } from '@/js-task-runner/result-validation'; @@ -24,6 +25,13 @@ describe('result validation', () => { }).not.toThrow(); }); + it('should throw a NonArrayOfObjectsError if the output is an array of arrays (empty)', () => { + expect(() => { + // @ts-expect-error Intentionally invalid + validateRunForAllItemsOutput([[]]); + }).toThrowError(NonArrayOfObjectsError); + }); + test.each([ ['binary', {}], ['pairedItem', {}], diff --git a/packages/@n8n/task-runner/src/js-task-runner/obj-utils.ts b/packages/@n8n/task-runner/src/js-task-runner/obj-utils.ts index 1e49e475d2..6e19249b24 100644 --- a/packages/@n8n/task-runner/src/js-task-runner/obj-utils.ts +++ b/packages/@n8n/task-runner/src/js-task-runner/obj-utils.ts @@ -1,4 +1,4 @@ -export function isObject(maybe: unknown): maybe is { [key: string]: unknown } { +export function isObject(maybe: unknown): maybe is object { return ( typeof maybe === 'object' && maybe !== null && !Array.isArray(maybe) && !(maybe instanceof Date) ); diff --git a/packages/@n8n/task-runner/src/js-task-runner/result-validation.ts b/packages/@n8n/task-runner/src/js-task-runner/result-validation.ts index 17c4df9a6e..d5999d1ce4 100644 --- a/packages/@n8n/task-runner/src/js-task-runner/result-validation.ts +++ b/packages/@n8n/task-runner/src/js-task-runner/result-validation.ts @@ -50,20 +50,26 @@ function validateItem({ json, binary }: INodeExecutionData, itemIndex: number) { } } +export class NonArrayOfObjectsError extends ValidationError { + constructor() { + super({ + message: "Code doesn't return items properly", + description: 'Please return an array of objects, one for each item you would like to output.', + }); + } +} + /** * Validates the output of a code node in 'Run for All Items' mode. */ export function validateRunForAllItemsOutput( executionResult: INodeExecutionData | INodeExecutionData[] | undefined, ) { - if (typeof executionResult !== 'object') { - throw new ValidationError({ - message: "Code doesn't return items properly", - description: 'Please return an array of objects, one for each item you would like to output.', - }); - } - if (Array.isArray(executionResult)) { + for (const item of executionResult) { + if (!isObject(item)) throw new NonArrayOfObjectsError(); + } + /** * If at least one top-level key is an n8n item key (`json`, `binary`, etc.), * then require all item keys to be an n8n item key. @@ -81,6 +87,8 @@ export function validateRunForAllItemsOutput( validateTopLevelKeys(item, index); } } + } else if (!isObject(executionResult)) { + throw new NonArrayOfObjectsError(); } const returnData = normalizeItems(executionResult);