n8n-io/n8n · error · ExpressionExtensionError

${fnName}(): all array elements must be numbers

Error message

${fnName}(): all array elements must be numbers

What it means

Thrown as ExpressionExtensionError by ensureNumberArray(), the shared guard used by the numeric array extensions sum(), min(), max(), and average(). It fires when any element of the array is not of type 'number'. fnName is substituted so the message names the exact function (e.g. 'sum(): all array elements must be numbers'). Note: string elements that look numeric are tolerated inside sum/min/max (parseFloat is applied), but the guard still rejects them because the check runs BEFORE the parseFloat path.

Source

Thrown at packages/@n8n/expression-runtime/src/extensions/array-extensions.ts:83

	return len ? value[randomInt(len)] : undefined;
}

function unique(value: unknown[], extraArgs: string[]): unknown[] {
	const mapForEqualityCheck = (item: unknown): unknown => {
		if (extraArgs.length > 0 && item && typeof item === 'object') {
			return extraArgs.reduce<Record<string, unknown>>((acc, key) => {
				acc[key] = (item as Record<string, unknown>)[key];
				return acc;
			}, {});
		}
		return item;
	};
	return uniqWith(value, (a, b) => isEqual(mapForEqualityCheck(a), mapForEqualityCheck(b)));
}

const ensureNumberArray = (arr: unknown[], { fnName }: { fnName: string }) => {
	if (arr.some((i) => typeof i !== 'number')) {
		throw new ExpressionExtensionError(`${fnName}(): all array elements must be numbers`);
	}
};

function sum(value: unknown[]): number {
	ensureNumberArray(value, { fnName: 'sum' });

	return value.reduce((p: number, c: unknown) => {
		if (typeof c === 'string') {
			return p + parseFloat(c);
		}
		if (typeof c !== 'number') {
			return NaN;
		}
		return p + c;
	}, 0);
}

function min(value: unknown[]): number {

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Coerce the array to numbers before calling the function: .map(x => Number(x)).sum().
  2. Filter out non-numeric values: .filter(x => typeof x === 'number').sum().
  3. Fix the upstream data source so numeric fields are parsed as numbers, not strings.
  4. Validate with a type guard before calling: if (arr.every(x => typeof x === 'number')).

Example fix

// before — numbers arrive as strings from JSON/CSV
{{ $json.prices.sum() }} // throws: 'sum(): all array elements must be numbers'
// after — coerce to numbers first
{{ $json.prices.map(p => Number(p)).sum() }}
Defensive patterns

Strategy: type-guard

Validate before calling

function assertAllNumbers(arr, fnName) {
  if (arr.some(x => typeof x !== 'number')) throw new TypeError(`${fnName}(): all array elements must be numbers`);
}
// usage: const safe = arr.filter(x => typeof x === 'number');
//        assertAllNumbers(safe, 'sum');

Type guard

function isNumberArray(arr) { return Array.isArray(arr) && arr.every(x => typeof x === 'number'); }

Try / catch

try {
  result = arr.sum();
} catch (e) {
  if (e.name === 'ExpressionExtensionError' && /must be numbers/i.test(e.message)) {
    // coerce: result = arr.map(Number).sum();
  }
}

Prevention

When it happens

Trigger: Calling .sum(), .min(), .max(), or .average() on an array containing a non-number element: a string, boolean, object, null, or undefined. Example: ['1','2','3'].sum() throws because the elements are strings (typeof !== 'number'), even though they are numeric strings.

Common situations: JSON data where numbers arrive as strings (e.g. from a CSV or API returning quoted numbers). An array with a null or missing value mixed into numeric data. A user assuming .sum() coerces strings like JS's implicit '+' would.

Related errors


AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12). Data as JSON: /api/errors/d08e5c360b0e6af0. Report an issue: GitHub.