n8n-io/n8n · error · ExpressionExtensionError
difference(): expected array arg, e.g. .difference([1, 2, 3,
Error message
difference(): expected array arg, e.g. .difference([1, 2, 3, 4])
What it means
Thrown as ExpressionExtensionError by the .difference() array extension when its argument is not an array. difference() returns elements in the base array that are not present in the other array; a non-array argument cannot be scanned for membership, so it is rejected up front.
Source
Thrown at packages/@n8n/expression-runtime/src/extensions/array-extensions.ts:286
function union(value: unknown[], extraArgs: unknown[][]): unknown[] {
const [others] = extraArgs;
if (!Array.isArray(others)) {
throw new ExpressionExtensionError('union(): expected array arg, e.g. .union([1, 2, 3, 4])');
}
const newArr: unknown[] = Array.from(value);
for (const v of others) {
if (newArr.findIndex((w) => isEqual(w, v)) === -1) {
newArr.push(v);
}
}
return unique(newArr, []);
}
function difference(value: unknown[], extraArgs: unknown[][]): unknown[] {
const [others] = extraArgs;
if (!Array.isArray(others)) {
throw new ExpressionExtensionError(
'difference(): expected array arg, e.g. .difference([1, 2, 3, 4])',
);
}
const newArr: unknown[] = [];
for (const v of value) {
if (others.findIndex((w) => isEqual(w, v)) === -1) {
newArr.push(v);
}
}
return unique(newArr, []);
}
function intersection(value: unknown[], extraArgs: unknown[][]): unknown[] {
const [others] = extraArgs;
if (!Array.isArray(others)) {
throw new ExpressionExtensionError(
'intersection(): expected array arg, e.g. .intersection([1, 2, 3, 4])',
);View on GitHub (pinned to 5ac6606e81)
Solutions
- Pass an array: .difference([1,2,3,4]).
- If the argument is dynamic, ensure it is an array before calling: Array.isArray(arg) ? .difference(arg) : .difference([arg]).
- Coerce single values into a one-element array when a difference with a scalar is intended.
- Confirm the upstream expression yields an array.
Example fix
// before — scalar argument
{{ $json.ids.difference($json.excluded) }} // if excluded is a number, throws
// after — ensure array argument
{{ $json.ids.difference(Array.isArray($json.excluded) ? $json.excluded : [$json.excluded]) }} Defensive patterns
Strategy: type-guard
Validate before calling
function differenceSafe(arr, others) {
if (!Array.isArray(others)) throw new TypeError('difference(): expected array arg');
return arr.filter(x => !others.includes(x));
} Type guard
function isDifferenceArgValid(others) { return Array.isArray(others); } Try / catch
try {
result = arr.difference(others);
} catch (e) {
if (e.name === 'ExpressionExtensionError' && /difference.*array/i.test(e.message)) {
// ensure others is an array: arr.difference(Array.isArray(others) ? others : [others])
}
} Prevention
- Always pass an array: .difference([1,2,3,4]).
- Coerce scalars: .difference(Array.isArray(x) ? x : [x]).
- Guard with Array.isArray(arg) before calling.
- Confirm upstream expressions that produce the argument yield an array.
When it happens
Trigger: Calling .difference() with a non-array: .difference(5), .difference('abc'), .difference({a:1}), or with undefined where the harness passes a non-array. The expected form is .difference([1,2,3,4]).
Common situations: Passing a scalar or object instead of an array. A template variable resolving to a single value. Forgetting the brackets. Same shape as the union/intersection guards.
Related errors
- arguments must be passed to pluck
- smartJoin(): expected two string args, e.g. .smartJoin("name
- chunk(): expected non-zero numeric arg, e.g. .chunk(5)
- renameKeys(): expected an even amount of args: from1, to1 [,
- merge(): expected object arg
AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12).
Data as JSON: /api/errors/ac8ec15ae2d84355.
Report an issue: GitHub.