data/skills/n8n-code-tool/ERROR_PATTERNS.md
The most common failure modes for @n8n/n8n-nodes-langchain.toolCode, with exact error strings, root causes, and fixes.
"Cannot assign to read only property 'name' of object: Error: No execution data available"Full message (wrapped by n8n):
There was an error: "Cannot assign to read only property 'name' of object 'Error: No execution data available'"
Cause: Calling $fromAI() inside the Code Tool sandbox. $fromAI() is a helper intended for other tool-enabled nodes (HTTP Request Tool, SendGrid Tool, toolWorkflow) where AI-supplied values flow through workflow execution data. The Code Tool sandbox has no execution data — it receives input directly via query. The helper throws, n8n tries to annotate the error's name property, and that assignment fails because the error object is frozen.
Fix: remove $fromAI(). Read from query (or define an input schema, see INPUT_SCHEMA.md).
// ❌ Broken
const price = $fromAI('price', 'Car price in SEK', 'number');
// ✅ Unstructured — parse a JSON string
const params = JSON.parse(query);
const price = Number(params.price);
// ✅ Structured — with specifyInputSchema: true
const { price } = query;
"Wrong output type returned"Cause: You returned the workflow item format ([{json: {...}}]) from the Code Tool. That format is for regular Code nodes; tools follow the LangChain contract and must return a string.
Fix: return a string. For structured output, stringify:
// ❌ Broken
return [{ json: { monthly_payment: 5405 } }];
// ✅ Fixed
return JSON.stringify({ monthly_payment: 5405 });
"The response property should be a string, but it is an <type>"Where <type> is object, undefined, function, etc.
Cause: You returned a bare object, array, or nothing at all.
| Returned value | Error says | Fix |
|---|---|---|
{ result: 42 } | ...is an object | JSON.stringify({ result: 42 }) |
[1, 2, 3] | ...is an object | JSON.stringify([1, 2, 3]) |
(no return) | ...is an undefined | Add a return |
undefined | ...is an undefined | Return something |
Numbers are fine — n8n auto-converts them to strings:
return 42; // ✅ becomes "42"
Booleans are NOT auto-converted — stringify explicitly:
return String(someBoolean); // ✅
return JSON.stringify(someBoolean); // ✅
Symptom: the agent answers from its own reasoning and ignores the tool. No tool invocation shows up in the execution trace.
Common causes and fixes:
Generic name. Default names like Code Tool or My Tool give the LLM no signal.
calculate_car_loan, search_orders, lookup_customer.Description doesn't state the trigger. "Calculates things" is too vague.
"Use this whenever the user asks about monthly cost, loan breakdown, or total interest."Tool isn't wired. The node sits in the canvas but isn't connected to the AI Agent's ai_tool input.
connections block has "<tool_name>": { "ai_tool": [[{ "node": "AI Agent", "type": "ai_tool", "index": 0 }]] }.Name violates [A-Za-z0-9_]+. Spaces, hyphens, and emoji in the tool name cause silent skip on v1.1+.
snake_case_only.querySymptom: your JSON.parse(query) throws, or fields come through as wrong types.
Causes:
Fixes, in order of preference:
Switch to structured mode. Set specifyInputSchema: true and define fields. The LLM now gets a typed schema and n8n validates before your code runs.
Give a concrete example in the description. LLMs imitate examples well:
Call with a single JSON string. Example:
{"price":439900,"down_payment":87980,"interest_rate":6.95}
Coerce defensively:
const params = JSON.parse(query);
const price = Number(params.price);
if (!isFinite(price)) throw new Error('price must be numeric');
"$helpers is not defined" / "$input is not defined"Cause: you assumed the Code Tool sandbox exposes the same helpers as the Code node. It doesn't.
Unavailable in Code Tool:
$input, $json, $binary$node["OtherNode"]$helpers.httpRequest()$jmespath()this.getContext(...), $getWorkflowStaticData(...)$fromAI()Fix:
$fromAI() in URL/body).toolWorkflow) — its sub-workflow has a full Code node sandbox."name 'query' is not defined"Cause: in Python, the input variable is _query (underscore prefix), not query.
# ❌ Broken
result = process(query)
# ✅ Fixed
result = process(_query)
Before saving a Code Tool:
$fromAI() in the code body$input, $json, $helpers — not in this sandboxquery (JS) or _query (Python)return a string (or a number that auto-converts)JSON.stringify(...)ai_tool connectionspecifyInputSchema: truequery the LLM sent.return JSON.stringify({ received_query: query, result: /* ... */ });
query, running it manually, then swapping back.