Most Code node failures in n8n are not bugs in your logic. They are format problems: n8n expected an array of items and received something else. The error names are precise once you know the rule behind them. Here are the five you will meet most often, with the fix for each.
In short. Return [{ json: {...} }]: an array, of objects, each with a json key that is itself an object. In "Run Once for Each Item" mode return a single item (return $input.item;). Check the mode before anything else, because $json only exists in per-item mode.
Error 1: "Code doesn't return items properly"
The code returned something that is not an array of items, for example a bare object or an array of plain values.
Convert any list into items with map:
Error 2: "A 'json' property isn't an object"
The json key points to an array or a primitive.
This often happens after an API returns a list and you assign it directly to json. Either wrap it as above, or split it into one item per element:
Error 3: "Code doesn't return an object"
The code returned nothing (no return line) or returned undefined. The documentation adds a less obvious cause: you referenced a field that does not exist in this execution, so the value you returned was undefined.
In per-item mode, return the item, not an array:
Error 4: "$json is not defined" or "items is not defined"
$json only exists in "Run Once for Each Item" mode. In the default "Run Once for All Items" mode, use $input.all().
items comes from the old Function node. The Code node replaced Function and Function Item in n8n 0.198.0. Old snippets that use items should be rewritten with $input.all().
Error 5: "'import' and 'export' may only appear at the top level"
The sandbox does not support ES modules. Use require(), and on self-hosted n8n allow the module first. Full steps in our guide to the Cannot find module error.
A safe template to start from
Paste this in any new Code node in default mode. It keeps the format right while you write the logic in the middle.
How to debug faster
- Pin the previous node's output so you can rerun the Code node on the same data.
- Log the shape before returning:
console.log(JSON.stringify(out).slice(0, 500));, then read your browser console. - Validate the whole workflow export with our free n8n Workflow Validator, and test expressions with the n8n Expression Tester.
- When a field is missing on some items only, use optional chaining:
item.json.customer?.email ?? null.
Understanding n8n's data structure in two minutes
All four errors above come from one design choice: n8n passes data between nodes as a list of items, and each item has a fixed envelope.
-
jsonis required and must be an object. -
binaryis optional and holds files (see binary data in the Code node). -
pairedItemlinks an output item to the input item it came from. n8n uses it to resolve expressions such as$('Node').itemin later nodes. When your code returns the same items it received, the link is kept. When you create brand new items, later nodes may not be able to tell which input they came from.
Worked example: converting an API response safely
An API returns one item shaped like this:
You want one item per person. Three wrong attempts and the right one:
The last version survives an empty or malformed response. Pair it with "Always Output Data" if later nodes must run even when the list is empty.
Per-item mode, the other half of the confusion
In "Run Once for Each Item", the node runs once per input item and expects one item back, not an array.
Returning an array here, or returning $json (the inner object) instead of the item, triggers format errors. If you want to drop an item in per-item mode, the cleanest approach is to switch to All Items mode and filter.
Troubleshooting table
| Error or symptom | What n8n received | Fix |
|---|---|---|
| Code doesn't return items properly | Strings, numbers or plain values | Wrap each value: { json: { value } } |
| A 'json' property isn't an object | json is an array or primitive | Wrap or split into items |
| Code doesn't return an object | Nothing, or undefined | Add return, guard missing data |
$json is not defined | Default All Items mode | Use $input.all() or change mode |
| Later expression cannot find the paired item | New items without a link to inputs | Return derived items, or read with .first() / .all() |
Output shows [object Object] in text | An object inserted into a string | JSON.stringify(obj) |
Common mistakes to avoid
- Returning
$jsonin per-item mode. Return$input.item, which is the full item envelope. - Mixing
returninside loops. Areturninside aforloop ends the node after the first item. - Trusting the test data. The pinned sample always has every field. Production data does not.
Production checklist
- A return statement on every path, including early exits.
-
jsonalways an object; arrays wrapped or split into items. - Real production samples pinned for testing, including an empty response.
- Defensive reads with
?.for fields some records do not have.
Frequently asked questions
What format must the n8n Code node return?
An array of objects, each with a json key containing an object: [{ json: { key: 'value' } }]. In "Run Once for Each Item" mode, return a single item such as $input.item.
Why does my Code node work in testing but fail in production?
Usually because production data differs: a field is missing or an API returned an empty list. Guard optional fields with ?. and ??, and handle empty arrays before mapping them.
Can a Code node return binary data?
Yes. Items can carry a binary key next to json. See our guide to binary data in the Code node.
Does the Code node need a json key on every item?
Yes. Every returned item must have a json object, even if it is empty: { json: {} }.
What is pairedItem in n8n?
A link from an output item to the input item that produced it. n8n uses it to resolve $('Node').item in later nodes. Returning transformed input items keeps it automatically.
How do I return nothing from a Code node without an error?
Return an empty array: return [];. Enable "Always Output Data" in the node settings if the next nodes must still run.
Why does my Code node return only one item?
A return inside a loop, or reading $input.first() instead of $input.all(). Build an array and return it after the loop.
Tags
Steve founded PURIST, a workflow automation studio working with n8n, Make and Claude AI, and is the point of contact on every project. Prices and features in our articles come from vendor documentation and public pricing pages. How we research and score tools.