{"record":{"id":"d08e5c360b0e6af0","repo":"n8n-io/n8n","slug":"fnname-all-array-elements-must-be-numbers","errorCode":null,"errorMessage":"${fnName}(): all array elements must be numbers","messagePattern":"(.+?)\\(\\): all array elements must be numbers","errorType":"exception","errorClass":"ExpressionExtensionError","httpStatus":null,"severity":"error","filePath":"packages/@n8n/expression-runtime/src/extensions/array-extensions.ts","lineNumber":83,"sourceCode":"\treturn len ? value[randomInt(len)] : undefined;\n}\n\nfunction unique(value: unknown[], extraArgs: string[]): unknown[] {\n\tconst mapForEqualityCheck = (item: unknown): unknown => {\n\t\tif (extraArgs.length > 0 && item && typeof item === 'object') {\n\t\t\treturn extraArgs.reduce<Record<string, unknown>>((acc, key) => {\n\t\t\t\tacc[key] = (item as Record<string, unknown>)[key];\n\t\t\t\treturn acc;\n\t\t\t}, {});\n\t\t}\n\t\treturn item;\n\t};\n\treturn uniqWith(value, (a, b) => isEqual(mapForEqualityCheck(a), mapForEqualityCheck(b)));\n}\n\nconst ensureNumberArray = (arr: unknown[], { fnName }: { fnName: string }) => {\n\tif (arr.some((i) => typeof i !== 'number')) {\n\t\tthrow new ExpressionExtensionError(`${fnName}(): all array elements must be numbers`);\n\t}\n};\n\nfunction sum(value: unknown[]): number {\n\tensureNumberArray(value, { fnName: 'sum' });\n\n\treturn value.reduce((p: number, c: unknown) => {\n\t\tif (typeof c === 'string') {\n\t\t\treturn p + parseFloat(c);\n\t\t}\n\t\tif (typeof c !== 'number') {\n\t\t\treturn NaN;\n\t\t}\n\t\treturn p + c;\n\t}, 0);\n}\n\nfunction min(value: unknown[]): number {","sourceCodeStart":65,"sourceCodeEnd":101,"githubUrl":"https://github.com/n8n-io/n8n/blob/5ac6606e81f67bb9534255570cd4e86fd8101eee/packages/@n8n/expression-runtime/src/extensions/array-extensions.ts#L65-L101","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Coerce the array to numbers before calling the function: .map(x => Number(x)).sum().","Filter out non-numeric values: .filter(x => typeof x === 'number').sum().","Fix the upstream data source so numeric fields are parsed as numbers, not strings.","Validate with a type guard before calling: if (arr.every(x => typeof x === 'number'))."],"exampleFix":"// before — numbers arrive as strings from JSON/CSV\n{{ $json.prices.sum() }} // throws: 'sum(): all array elements must be numbers'\n// after — coerce to numbers first\n{{ $json.prices.map(p => Number(p)).sum() }}","handlingStrategy":"type-guard","validationCode":"function assertAllNumbers(arr, fnName) {\n  if (arr.some(x => typeof x !== 'number')) throw new TypeError(`${fnName}(): all array elements must be numbers`);\n}\n// usage: const safe = arr.filter(x => typeof x === 'number');\n//        assertAllNumbers(safe, 'sum');","typeGuard":"function isNumberArray(arr) { return Array.isArray(arr) && arr.every(x => typeof x === 'number'); }","tryCatchPattern":"try {\n  result = arr.sum();\n} catch (e) {\n  if (e.name === 'ExpressionExtensionError' && /must be numbers/i.test(e.message)) {\n    // coerce: result = arr.map(Number).sum();\n  }\n}","preventionTips":["Coerce numeric strings to Number before .sum()/.min()/.max()/.average(): .map(Number).sum().","Filter out null/undefined/non-numbers: .filter(x => typeof x === 'number').sum().","Fix upstream sources that deliver numbers as strings (CSV/API quoted numbers).","Guard with isNumberArray(arr) before calling."],"tags":["expression-runtime","array-extensions","numeric","type-coercion","sum-min-max-average"],"backgroundTag":null,"analyzedSha":"5ac6606e81f67bb9534255570cd4e86fd8101eee","analyzedAt":"2026-08-12T05:26:35.080Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}