Code doesn't return items properly
Your Code node is in Run Once for All Items mode and returned something that isn't an array of objects. n8n checks the shape of the return value before it looks at any of your data, so this fires even when the data inside is perfect.
The description under it always reads: "Please return an array of objects, one for each item you would like to output."
Exactly when it fires
Two conditions, and only two. Both come straight from n8n's validator:
The return value isn't an object at all. A string, a number, a boolean — or nothing, because a path through your code hit the end of the function without a
return. That last one is the most common cause by a distance, and it's invisible when you read the code, because thereturnyou're looking at is inside anif.You returned an array, but at least one element isn't an object.
return [1, 2, 3]andreturn ['a', 'b']both fail here. So does an array with anullhiding in it from a.map()that didn't cover every branch.
One consequence worth knowing: typeof null === 'object' in JavaScript, so
return null passes this check and fails further down with a different message.
If you're staring at this error, null is not what you returned.
The fix
The shape n8n wants is an array of objects, each with a json key:
return $input.all().map(item => ({
json: {
email: item.json.email,
domain: item.json.email.split('@')[1],
},
}));
Three checks that resolve almost every occurrence:
- Does every path return? Add a
return []as the last line of the function. An empty array is a valid, explicit "no output". - Are you returning the result of a
.forEach()?forEachreturnsundefined. You want.map(), or push into an array and return that. - Did an
awaitgo missing? Returning a Promise fails this check.awaitit.
The wrapping rule nobody documents
n8n will wrap a bare object in json for you — but only under a specific condition,
and getting it half-right is what produces the confusing failures.
n8n reserves exactly five top-level item keys:
json binary pairedItem error index
The rule:
- If none of your object's top-level keys is one of those five, n8n wraps the whole
object in
jsonfor you. Soreturn [{ name: 'Ada' }]works fine and becomes{ json: { name: 'Ada' } }. - If at least one key is reserved and at least one isn't, n8n refuses, because you
have almost certainly put a property on the item that you meant to put inside
json.
So this is fine:
return [{ name: 'Ada', role: 'admin' }]; // wrapped for you
and this throws — not with the error at the top of this page, but with Invalid output format, described as "An output item contains the reserved key json. To
get around this, please wrap each item in an object, under a key called json.":
return [{ json: { name: 'Ada' }, role: 'admin' }]; // mixed. refused.
The fix is to put the stray key where it belongs:
return [{ json: { name: 'Ada', role: 'admin' } }];
If no reserved key is present but an unknown one is flagged, the message is
Unknown top-level item key: <yourKey>, described as "Access the properties of an
item under .json, e.g. item.json" — same mistake, caught on a different path.
Wrong-mode errors look different, and that's useful
If you're in Run Once for Each Item mode, you get different wording, and the wording tells you which mistake you made:
| Message | You did this |
|---|---|
Code doesn't return an object |
returned a string/number/undefined from per-item mode |
Code doesn't return a single object |
returned an array from per-item mode |
The second one's description says it outright: "If you need to output multiple items,
please use the 'Run Once for All Items' mode instead." In per-item mode you return one
bare object — return { json: { … } } — not an array of one.
So: if you're reading "Code doesn't return items properly", you are definitely in Run Once for All Items mode. That's already one thing narrowed down.
Reading the bracketed suffix
n8n appends location information to these messages when it has it:
… [item 4]— it knows which item failed… [line 12]— it knows which line… [line 12, for item 4]— both
So A 'json' property isn't an object [item 4] means item 4 specifically. Items 0–3
were fine, which usually means the failure is data-dependent — a field that's missing
on some records, not a mistake in the shape of your code.
Related errors from the same node
A 'json' property isn't an object— you returned the right outer shape, but ajsonkey points at a string, a number orundefined. Description: "In the returned data, every key named 'json' must point to an object." Same forA 'binary' property isn't an object.`items` is not defined. Did you mean `$input.all()`?— you're using the old Function node's variable. n8n adds that suggestion itself, but only when you haven't declareditemsyourself. The per-item equivalent is`item` is not defined. Did you mean `$input.item.json`?Can't use .first() here— described as "This is only available in 'Run Once for All Items' mode". Thrown for.first(),.last(),.all()and.itemMatching()used in per-item mode.- Paired item data … is unavailable — the downstream consequence of returning items
from this node without
pairedItem.
Why this happens at all
The Code node sits on a boundary. Inside it you have ordinary JavaScript values; the moment you return, n8n needs items — objects in a fixed envelope that the rest of the workflow can carry, link and display. Nothing can translate an arbitrary JS value into that envelope unambiguously, so n8n validates instead of guessing, and throws at the boundary rather than letting a malformed item travel three nodes and fail somewhere that makes no sense.
The wrapping rule above is the one place n8n does guess — and it only guesses when your object gives it no reason to think you meant something else.
Sources: packages/nodes-base/nodes/Code/result-validation.ts,
ValidationError.ts, JsCodeValidator.ts and reserved-key-found-error.ts in n8n's
repository, read directly. n8n's Code node docs do not list these error strings.
Last verified 15 September 2026 against n8n 2.39.5 (source read on master @ 2.40.0). n8n changes these messages between releases; if the wording you see differs, the version above is what this page was checked against.