[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6JE5HADKKFEVM1TJCSW3MN2":3,"skill-same:01M6JE5HADKKFEVM1TJCSW3MN2":72},{"skillNo":4,"name":5,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":6,"repositoryNo":11,"starsCount":12,"licenseSpdxId":13,"licenseFileUrl":6,"sourceHtmlUrl":14,"categories":15,"keywords":26,"publishedAt":31,"linkOnly":32,"markdownContent":33,"markdownBody":34,"frontMatter":35,"refName":36,"commitSha":37,"skillDirectory":38,"forksCount":39,"repositoryHtmlUrl":40,"repositoryHomepageUrl":41,"ownerHtmlUrl":42,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":43,"install":44,"resources":57},"01M6JE5HADKKFEVM1TJCSW3MN2","n8n-code-tool",null,"S3YED\u002Fappie-kit","S3YED","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F62743867?v=4","01M6JBKBRRVP6KMS0VWZ27T3R6","01M6JBKBX0KG30284PW1DBYJT1",14,"MIT","https:\u002F\u002Fgithub.com\u002FS3YED\u002Fappie-kit\u002Fblob\u002Fmaster\u002Fskills\u002Fintegrations\u002Fn8n-workflows\u002Fn8n-code-tool\u002FSKILL.md",[16,21],{"categoryNo":17,"categoryName":18,"taxonomyType":19,"taxonomyTypeDesc":20},"01JBSEEDCAT000000000000023","Skill与智能体开发","SCENARIO","使用场景",{"categoryNo":22,"categoryName":23,"taxonomyType":24,"taxonomyTypeDesc":25},"01JBSEEDCAT000000000000030","开发工程师","PROFESSION","适用职业",[27,28,29,30],"code","tool","n8n","n8n code tool","2026-11-10 10:12:30",false,"---\nname: n8n-code-tool\ndescription: Write JavaScript or Python for the n8n Custom Code Tool (@n8n\u002Fn8n-nodes-langchain.toolCode) — the AI-agent-callable tool, NOT the workflow Code node. Use when building a Code Tool attached to an AI Agent, writing code that an LLM will invoke, parsing the `query` input, returning a string result, defining an input schema for structured arguments (specifyInputSchema, jsonSchemaExample, DynamicStructuredTool), or troubleshooting errors like \"Wrong output type returned\", \"No execution data available\", \"The response property should be a string, but it is an object\", \"Cannot assign to read only property 'name'\", or an AI agent that refuses to call the tool. Covers the critical differences between Code node and Code Tool: return format (string vs `[{json:{...}}]`), unavailability of `$fromAI`\u002F`$input`\u002F`$helpers` in the Code Tool sandbox, naming rules for AI invocation, and when to use `toolWorkflow`\u002FHTTP Request Tool instead.\n---\n\n# n8n Custom Code Tool\n\nExpert guidance for writing code inside `@n8n\u002Fn8n-nodes-langchain.toolCode` — the tool an AI Agent can invoke, **not** the regular workflow Code node.\n\n---\n\n## ⚠️ This is NOT the Code node\n\nThe Custom Code Tool looks like a Code node in the editor — same JavaScript editor, similar layout — but it is a **completely different node** from a different package with a **different runtime contract**.\n\n| | Code node | Custom Code Tool |\n|---|---|---|\n| **Node type** | `n8n-nodes-base.code` | `@n8n\u002Fn8n-nodes-langchain.toolCode` |\n| **Package** | `n8n-nodes-base` | `@n8n\u002Fn8n-nodes-langchain` |\n| **Invoked by** | Previous node (workflow flow) | AI Agent (LangChain) |\n| **Input** | `$input.all()` — item stream | `query` — string or object from LLM |\n| **Return** | `[{json: {...}}]` (items array) | **A string** |\n| **`$fromAI()`** | N\u002FA | **Not available** (see Errors) |\n| **HTTP helper** | `this.helpers.httpRequest` (auth helpers blocked) | Not exposed to the tool sandbox |\n| **State** | Per-run execution data | No `getContext`, no `$getWorkflowStaticData` |\n\n**If you treat it like a Code node, it fails.** The rest of this skill covers the Code Tool's actual contract.\n\n---\n\n## Quick Start\n\n### Minimal JavaScript Code Tool\n\n```javascript\n\u002F\u002F `query` is whatever the AI sent (a string by default)\nreturn `You asked: ${query}`;\n```\n\n### Minimal Python Code Tool\n\n```python\n# `_query` is whatever the AI sent (a string by default)\nreturn f\"You asked: {_query}\"\n```\n\n### Essential Rules\n\n1. **Return a string.** Numbers are auto-converted. Anything else throws `\"The response property should be a string, but it is an object\"`.\n2. **Input variable is fixed**: `query` (JS), `_query` (Python). You cannot rename it.\n3. **Do NOT use `$fromAI()`** inside the Code Tool sandbox — it throws `\"No execution data available\"`.\n4. **Do NOT use `[{json: {...}}]`** return format — that's for Code nodes. Throws `\"Wrong output type returned\"`.\n5. **Use a descriptive tool name** (letters\u002Fnumbers\u002Funderscores, v1.1+). The agent calls the tool by its name.\n6. **Write a precise description** — the LLM decides whether to invoke the tool based on it.\n\n---\n\n## The Two Input Modes\n\nThe Code Tool has two input shapes, controlled by `specifyInputSchema`:\n\n### Mode 1: Unstructured (default, `specifyInputSchema: false`)\n\nThe AI passes **a single string** as `query`. If you need multiple fields, the AI has to stuff them into that one string and you parse them out. In practice, LLMs will happily pass a JSON string if your description tells them to.\n\n```javascript\n\u002F\u002F Parse a JSON string the AI sent\nlet params;\ntry {\n  params = typeof query === 'string' ? JSON.parse(query) : query;\n} catch (e) {\n  throw new Error('Expected a JSON object. Parser said: ' + e.message);\n}\nconst price = Number(params.price);\nconst months = Number(params.months);\n\u002F\u002F ...\nreturn JSON.stringify({ monthly_payment: \u002F* ... *\u002F });\n```\n\n**Pros**: simplest to set up, one field to describe.\n**Cons**: no schema validation — if the LLM forgets a field, the tool throws at runtime.\n\n**Best for**: quick prototypes, tools with one natural input (a question, a URL, a text blob).\n\n### Mode 2: Structured (`specifyInputSchema: true`)\n\nThe tool becomes a LangChain `DynamicStructuredTool`. The LLM sees a typed argument schema and passes a **validated object** as `query`. You access fields directly.\n\n```javascript\n\u002F\u002F query is now an object matching your schema\nconst price = query.price;\nconst months = query.months;\nconst residual_percent = query.residual_percent;\n\nconst monthly = computeAnnuity(price, months, residual_percent);\nreturn JSON.stringify({ monthly_payment: monthly });\n```\n\nSchema is defined via either:\n- `schemaType: \"fromJson\"` + `jsonSchemaExample` (n8n v≥1.3) — paste an example JSON, n8n infers the schema\n- `schemaType: \"manual\"` + `inputSchema` — write a full JSON Schema yourself\n\n**Pros**: LLM gets type hints, invalid calls rejected before your code runs, cleaner code.\n**Cons**: a little more setup; requires n8n version with schema support.\n\n**Best for**: production tools with multiple typed parameters (calculators, API wrappers, anything with numeric fields the LLM tends to stringify).\n\n**See**: [INPUT_SCHEMA.md](INPUT_SCHEMA.md) for complete schema setup.\n\n---\n\n## Return Format\n\n**The return value must be a string.** The LLM reads it as the tool's observation.\n\n```javascript\n\u002F\u002F ✅ String\nreturn \"42\";\n\n\u002F\u002F ✅ Number (auto-converted to string by n8n)\nreturn 42;\n\n\u002F\u002F ✅ JSON-encoded structured result (recommended for rich output)\nreturn JSON.stringify({ result: 42, currency: \"SEK\" });\n\n\u002F\u002F ❌ Raw object → \"The response property should be a string, but it is an object\"\nreturn { result: 42 };\n\n\u002F\u002F ❌ Workflow item format → \"Wrong output type returned\"\nreturn [{ json: { result: 42 } }];\n\n\u002F\u002F ❌ Array → \"The response property should be a string, but it is an object\"\nreturn [1, 2, 3];\n```\n\n### Best practice: JSON-stringify structured results\n\nWhen your tool has more than a trivial scalar output, return a JSON string:\n\n```javascript\nreturn JSON.stringify({\n  monthly_payment_sek: 5405,\n  loan_amount: 351920,\n  total_cost_of_credit: 63295\n});\n```\n\nThe LLM parses JSON reliably and can pick the fields it needs to present to the user.\n\n### Error handling: the agent reads your failures\n\nErrors don't just stop the workflow — they go back to the LLM, which usually corrects its call and retries. Use that:\n\n```javascript\n\u002F\u002F Option A: throw — n8n surfaces the message to the agent\nif (!isFinite(price)) throw new Error('price must be a number, e.g. 439900');\n\n\u002F\u002F Option B: return an error string — agent reads it like any tool result\nif (!isFinite(price)) return JSON.stringify({ error: 'price must be a number, e.g. 439900' });\n```\n\nEither way, write error messages **for the LLM**: state what was wrong and what a valid call looks like. A bare `throw new Error('invalid input')` wastes the retry; an instructive message usually fixes the next call.\n\n---\n\n## Tool Name and Description\n\nThese fields are NOT documentation — they are the **tool contract the LLM sees**. Treat them as prompt engineering.\n\n### Name\n- Must match `[A-Za-z0-9_]+` (v1.1+). No spaces, no hyphens, no emoji.\n- Use a verb-y descriptive name: `calculate_car_loan`, `get_weather`, `search_orders`.\n- The agent calls the tool by this name. `Code Tool` (the default) is useless — the agent won't know when to call it.\n\n### Description\n- Explain **when** to use it and **what** to send.\n- If unstructured mode, **include an example of the JSON string** the LLM should send.\n- If structured mode, the schema speaks for itself — just describe purpose.\n\n**Unstructured example (JSON-in-string pattern):**\n```\nDeterministiskt beräknar månadskostnad för billån. Anropa med EN JSON-sträng:\n{\"price\":439900,\"down_payment\":87980,\"interest_rate\":6.95,\"months\":36,\"residual_percent\":50}\nFält: price (SEK), down_payment (SEK), interest_rate (% per år), months, residual_percent (0-99).\n```\n\n**Structured example (schema-defined):**\n```\nDeterministically computes the monthly car-loan payment given price, down payment, \nannual interest rate, term, and residual percent. Use whenever the user asks for \nmonthly cost, total credit cost, or loan breakdown.\n```\n\n---\n\n## Top Errors and Fixes\n\n### Error 1: `\"There was an error: 'Cannot assign to read only property \\\"name\\\" of object: Error: No execution data available'\"`\n\n**Cause**: you called `$fromAI()` inside the Code Tool sandbox.\n\n**Fix**: `$fromAI()` is a helper for **other** tool-enabled nodes (HTTP Request Tool, SendGrid Tool, `toolWorkflow`, etc.) — it's not exposed inside `toolCode`. Read the AI's input from `query` directly (or use `specifyInputSchema` for structured fields).\n\n### Error 2: `\"Wrong output type returned\"`\n\n**Cause**: you returned a workflow-style array like `[{ json: { ... } }]`. That's the Code **node** contract, not the Code **Tool** contract.\n\n**Fix**: return a string. For structured data, `return JSON.stringify(output)`.\n\n### Error 3: `\"The response property should be a string, but it is an object\"`\n\n**Cause**: you returned a plain object or array.\n\n**Fix**: `JSON.stringify()` the result, or coerce to a string.\n\n### Error 4: AI never calls the tool\n\n**Cause**: tool name is generic (`Code Tool`, `My Tool`) or description doesn't clearly state when to use it.\n\n**Fix**: rename to a verb-y name (`calculate_car_loan`), and rewrite the description to explicitly state the trigger conditions (e.g. \"Use this whenever the user asks about monthly cost\").\n\n### Error 5: AI sends garbage into `query`\n\n**Cause**: unstructured tool with a vague description. The LLM guesses at the format.\n\n**Fix**: either (a) include a concrete JSON example in the description, or (b) switch to `specifyInputSchema: true` so the LLM gets a typed schema.\n\n**See**: [ERROR_PATTERNS.md](ERROR_PATTERNS.md) for full catalog with reproductions.\n\n---\n\n## What's NOT Available in the Sandbox\n\nThe Code Tool sandbox is **narrower** than the Code node sandbox. Don't assume helpers carry over:\n\n| Helper | Code node | Code Tool |\n|---|---|---|\n| `$input.all()`, `$input.first()`, `$input.item` | ✅ | ❌ |\n| `$node[\"NodeName\"]` | ✅ | ❌ |\n| `$json`, `$binary` | ✅ | ❌ |\n| `$fromAI()` | ❌ | ❌ (despite sitting next to an AI agent) |\n| `this.helpers.httpRequest()` | ✅ | ❌ |\n| `DateTime` (Luxon) | ✅ | ✅ (standard in JS sandbox) |\n| `$jmespath()` | ✅ | ❌ |\n| `this.getContext(...)` | ✅ | ❌ |\n| `$getWorkflowStaticData(...)` | ✅ | ❌ |\n\n**Implication**: the Code Tool is for **pure computation**. If you need an HTTP call, an API lookup, or cross-invocation state, use a different tool node:\n- HTTP Request Tool for external API calls\n- `toolWorkflow` (Call Sub-workflow Tool) for multi-step logic with access to the full Code node sandbox\n- MCP \u002F database tools for persistent state\n\n---\n\n## When to Use Code Tool vs Alternatives\n\nUse **Code Tool** when:\n- ✅ Pure deterministic computation (math, parsing, formatting, validation)\n- ✅ Lightweight transformations the LLM shouldn't do itself (precision math, regex)\n- ✅ You want the code inline in the workflow, not in a separate sub-workflow\n\nUse **`toolWorkflow`** (Call Sub-workflow Tool) when:\n- ✅ You need multiple parameters with clean `$fromAI()` typing\n- ✅ You need access to `this.helpers`, credentials, or other nodes\n- ✅ Logic is reusable across agents\n- ✅ You want structured typed inputs WITHOUT writing a JSON Schema\n\nUse **HTTP Request Tool** when:\n- ✅ The tool is fundamentally a single API call\n- ✅ You want per-parameter `$fromAI()` bindings in URL\u002Fquery\u002Fbody\n\n**Rule of thumb**: if you find yourself wanting `$fromAI()`, you probably want `toolWorkflow` instead of `toolCode`.\n\n---\n\n## Complete Working Example\n\nA production calculator tool (unstructured, JSON-in-string pattern):\n\n```json\n{\n  \"parameters\": {\n    \"name\": \"calculate_car_loan\",\n    \"description\": \"Computes monthly car-loan payment using an annuity formula with residual\u002Fballoon. Call with a single JSON string. Example: {\\\"price\\\":439900,\\\"down_payment\\\":87980,\\\"interest_rate\\\":6.95,\\\"months\\\":36,\\\"residual_percent\\\":50,\\\"setup_fee\\\":695,\\\"monthly_admin_fee\\\":59}. Required: price, down_payment, interest_rate, months, residual_percent. Optional: setup_fee, monthly_admin_fee (default 0).\",\n    \"language\": \"javaScript\",\n    \"jsCode\": \"let params;\\ntry {\\n  params = typeof query === 'string' ? JSON.parse(query) : query;\\n} catch (e) {\\n  throw new Error('Invalid JSON: ' + e.message);\\n}\\n\\nconst price           = Number(params.price);\\nconst down_payment    = Number(params.down_payment);\\nconst interest_rate   = Number(params.interest_rate);\\nconst months          = Number(params.months);\\nconst residual_percent= Number(params.residual_percent);\\nconst setup_fee       = Number(params.setup_fee ?? 0) || 0;\\nconst monthly_admin_fee = Number(params.monthly_admin_fee ?? 0) || 0;\\n\\nif (!isFinite(price) || price \u003C= 0) throw new Error('price must be > 0');\\nif (down_payment \u003C 0 || down_payment >= price) throw new Error('down_payment must be in [0, price)');\\n\\nconst principal = price - down_payment;\\nconst residual  = price * (residual_percent \u002F 100);\\nconst r = interest_rate \u002F 100 \u002F 12;\\nconst growth = Math.pow(1 + r, months);\\nconst base = r === 0\\n  ? (principal - residual) \u002F months\\n  : (principal - residual \u002F growth) * r \u002F (1 - 1 \u002F growth);\\nconst monthly_payment = base + monthly_admin_fee;\\n\\nreturn JSON.stringify({\\n  monthly_payment_sek: Math.round(monthly_payment),\\n  loan_amount: Math.round(principal),\\n  residual_value_sek: Math.round(residual),\\n  total_cost_of_credit: Math.round(monthly_payment * months + residual + setup_fee - principal)\\n});\"\n  },\n  \"type\": \"@n8n\u002Fn8n-nodes-langchain.toolCode\",\n  \"typeVersion\": 1.3,\n  \"name\": \"calculate_car_loan\"\n}\n```\n\nWire it into an AI Agent via the `ai_tool` connection type.\n\n---\n\n## Integration with Other Skills\n\n**n8n-code-javascript**: the Code **node** skill. Most JavaScript patterns (arrays, map\u002Ffilter, DateTime) transfer — but I\u002FO contract is different. Don't copy data-access code.\n\n**n8n-node-configuration**: `specifyInputSchema` is a classic displayOptions-driven conditional field. Use `get_node({detail: \"standard\"})` on `@n8n\u002Fn8n-nodes-langchain.toolCode` to see schema-related properties.\n\n**n8n-workflow-patterns**: Code Tool sits inside the \"AI Agent with tools\" pattern. An agent typically has several tools; Code Tool is the \"local compute\" option.\n\n**n8n-validation-expert**: the three Code Tool errors listed above have clear signatures — if validation surfaces \"Wrong output type returned\", you know to switch from array-of-items to a string.\n\n---\n\n## Quick Reference Checklist\n\nBefore deploying a Code Tool:\n\n- [ ] **Node type** is `@n8n\u002Fn8n-nodes-langchain.toolCode` (not `nodes-base.code`)\n- [ ] **Tool name** is descriptive, verb-y, snake_case (e.g. `calculate_car_loan`)\n- [ ] **Description** states when to use the tool and (if unstructured) shows a JSON example\n- [ ] **Input** read from `query` (JS) or `_query` (Python)\n- [ ] **No `$fromAI()`** in the code body\n- [ ] **No `$input` \u002F `$json` \u002F `$helpers`** — those aren't in the sandbox\n- [ ] **Return** is a string (use `JSON.stringify()` for structured output)\n- [ ] **Wired** into an AI Agent via `ai_tool` connection\n- [ ] **Tested** with the exact kind of input the LLM will send (JSON in a string, or schema-validated object)\n\n---\n\n## Additional Resources\n\n- [INPUT_SCHEMA.md](INPUT_SCHEMA.md) — structured input (DynamicStructuredTool) in depth\n- [ERROR_PATTERNS.md](ERROR_PATTERNS.md) — full error catalog with causes and fixes\n\n### Official sources\n- [n8n Custom Code Tool docs](https:\u002F\u002Fdocs.n8n.io\u002Fintegrations\u002Fbuiltin\u002Fcluster-nodes\u002Fsub-nodes\u002Fn8n-nodes-langchain.toolcode\u002F)\n- [ToolCode source](https:\u002F\u002Fgithub.com\u002Fn8n-io\u002Fn8n\u002Fblob\u002Fmaster\u002Fpackages\u002F%40n8n\u002Fnodes-langchain\u002Fnodes\u002Ftools\u002FToolCode\u002FToolCode.node.ts) — the sandbox contract\n- [LangChain tool docs](https:\u002F\u002Fjs.langchain.com\u002Fdocs\u002Fmodules\u002Fagents\u002Ftools\u002F) — DynamicTool \u002F DynamicStructuredTool\n\n---\n\n**Remember**: the Code Tool is a LangChain tool wearing a Code-node UI. Contract is: **string in, string out**. Everything else follows from that.\n","# n8n Custom Code Tool\n\nExpert guidance for writing code inside `@n8n\u002Fn8n-nodes-langchain.toolCode` — the tool an AI Agent can invoke, **not** the regular workflow Code node.\n\n---\n\n## ⚠️ This is NOT the Code node\n\nThe Custom Code Tool looks like a Code node in the editor — same JavaScript editor, similar layout — but it is a **completely different node** from a different package with a **different runtime contract**.\n\n| | Code node | Custom Code Tool |\n|---|---|---|\n| **Node type** | `n8n-nodes-base.code` | `@n8n\u002Fn8n-nodes-langchain.toolCode` |\n| **Package** | `n8n-nodes-base` | `@n8n\u002Fn8n-nodes-langchain` |\n| **Invoked by** | Previous node (workflow flow) | AI Agent (LangChain) |\n| **Input** | `$input.all()` — item stream | `query` — string or object from LLM |\n| **Return** | `[{json: {...}}]` (items array) | **A string** |\n| **`$fromAI()`** | N\u002FA | **Not available** (see Errors) |\n| **HTTP helper** | `this.helpers.httpRequest` (auth helpers blocked) | Not exposed to the tool sandbox |\n| **State** | Per-run execution data | No `getContext`, no `$getWorkflowStaticData` |\n\n**If you treat it like a Code node, it fails.** The rest of this skill covers the Code Tool's actual contract.\n\n---\n\n## Quick Start\n\n### Minimal JavaScript Code Tool\n\n```javascript\n\u002F\u002F `query` is whatever the AI sent (a string by default)\nreturn `You asked: ${query}`;\n```\n\n### Minimal Python Code Tool\n\n```python\n# `_query` is whatever the AI sent (a string by default)\nreturn f\"You asked: {_query}\"\n```\n\n### Essential Rules\n\n1. **Return a string.** Numbers are auto-converted. Anything else throws `\"The response property should be a string, but it is an object\"`.\n2. **Input variable is fixed**: `query` (JS), `_query` (Python). You cannot rename it.\n3. **Do NOT use `$fromAI()`** inside the Code Tool sandbox — it throws `\"No execution data available\"`.\n4. **Do NOT use `[{json: {...}}]`** return format — that's for Code nodes. Throws `\"Wrong output type returned\"`.\n5. **Use a descriptive tool name** (letters\u002Fnumbers\u002Funderscores, v1.1+). The agent calls the tool by its name.\n6. **Write a precise description** — the LLM decides whether to invoke the tool based on it.\n\n---\n\n## The Two Input Modes\n\nThe Code Tool has two input shapes, controlled by `specifyInputSchema`:\n\n### Mode 1: Unstructured (default, `specifyInputSchema: false`)\n\nThe AI passes **a single string** as `query`. If you need multiple fields, the AI has to stuff them into that one string and you parse them out. In practice, LLMs will happily pass a JSON string if your description tells them to.\n\n```javascript\n\u002F\u002F Parse a JSON string the AI sent\nlet params;\ntry {\n  params = typeof query === 'string' ? JSON.parse(query) : query;\n} catch (e) {\n  throw new Error('Expected a JSON object. Parser said: ' + e.message);\n}\nconst price = Number(params.price);\nconst months = Number(params.months);\n\u002F\u002F ...\nreturn JSON.stringify({ monthly_payment: \u002F* ... *\u002F });\n```\n\n**Pros**: simplest to set up, one field to describe.\n**Cons**: no schema validation — if the LLM forgets a field, the tool throws at runtime.\n\n**Best for**: quick prototypes, tools with one natural input (a question, a URL, a text blob).\n\n### Mode 2: Structured (`specifyInputSchema: true`)\n\nThe tool becomes a LangChain `DynamicStructuredTool`. The LLM sees a typed argument schema and passes a **validated object** as `query`. You access fields directly.\n\n```javascript\n\u002F\u002F query is now an object matching your schema\nconst price = query.price;\nconst months = query.months;\nconst residual_percent = query.residual_percent;\n\nconst monthly = computeAnnuity(price, months, residual_percent);\nreturn JSON.stringify({ monthly_payment: monthly });\n```\n\nSchema is defined via either:\n- `schemaType: \"fromJson\"` + `jsonSchemaExample` (n8n v≥1.3) — paste an example JSON, n8n infers the schema\n- `schemaType: \"manual\"` + `inputSchema` — write a full JSON Schema yourself\n\n**Pros**: LLM gets type hints, invalid calls rejected before your code runs, cleaner code.\n**Cons**: a little more setup; requires n8n version with schema support.\n\n**Best for**: production tools with multiple typed parameters (calculators, API wrappers, anything with numeric fields the LLM tends to stringify).\n\n**See**: [INPUT_SCHEMA.md](INPUT_SCHEMA.md) for complete schema setup.\n\n---\n\n## Return Format\n\n**The return value must be a string.** The LLM reads it as the tool's observation.\n\n```javascript\n\u002F\u002F ✅ String\nreturn \"42\";\n\n\u002F\u002F ✅ Number (auto-converted to string by n8n)\nreturn 42;\n\n\u002F\u002F ✅ JSON-encoded structured result (recommended for rich output)\nreturn JSON.stringify({ result: 42, currency: \"SEK\" });\n\n\u002F\u002F ❌ Raw object → \"The response property should be a string, but it is an object\"\nreturn { result: 42 };\n\n\u002F\u002F ❌ Workflow item format → \"Wrong output type returned\"\nreturn [{ json: { result: 42 } }];\n\n\u002F\u002F ❌ Array → \"The response property should be a string, but it is an object\"\nreturn [1, 2, 3];\n```\n\n### Best practice: JSON-stringify structured results\n\nWhen your tool has more than a trivial scalar output, return a JSON string:\n\n```javascript\nreturn JSON.stringify({\n  monthly_payment_sek: 5405,\n  loan_amount: 351920,\n  total_cost_of_credit: 63295\n});\n```\n\nThe LLM parses JSON reliably and can pick the fields it needs to present to the user.\n\n### Error handling: the agent reads your failures\n\nErrors don't just stop the workflow — they go back to the LLM, which usually corrects its call and retries. Use that:\n\n```javascript\n\u002F\u002F Option A: throw — n8n surfaces the message to the agent\nif (!isFinite(price)) throw new Error('price must be a number, e.g. 439900');\n\n\u002F\u002F Option B: return an error string — agent reads it like any tool result\nif (!isFinite(price)) return JSON.stringify({ error: 'price must be a number, e.g. 439900' });\n```\n\nEither way, write error messages **for the LLM**: state what was wrong and what a valid call looks like. A bare `throw new Error('invalid input')` wastes the retry; an instructive message usually fixes the next call.\n\n---\n\n## Tool Name and Description\n\nThese fields are NOT documentation — they are the **tool contract the LLM sees**. Treat them as prompt engineering.\n\n### Name\n- Must match `[A-Za-z0-9_]+` (v1.1+). No spaces, no hyphens, no emoji.\n- Use a verb-y descriptive name: `calculate_car_loan`, `get_weather`, `search_orders`.\n- The agent calls the tool by this name. `Code Tool` (the default) is useless — the agent won't know when to call it.\n\n### Description\n- Explain **when** to use it and **what** to send.\n- If unstructured mode, **include an example of the JSON string** the LLM should send.\n- If structured mode, the schema speaks for itself — just describe purpose.\n\n**Unstructured example (JSON-in-string pattern):**\n```\nDeterministiskt beräknar månadskostnad för billån. Anropa med EN JSON-sträng:\n{\"price\":439900,\"down_payment\":87980,\"interest_rate\":6.95,\"months\":36,\"residual_percent\":50}\nFält: price (SEK), down_payment (SEK), interest_rate (% per år), months, residual_percent (0-99).\n```\n\n**Structured example (schema-defined):**\n```\nDeterministically computes the monthly car-loan payment given price, down payment, \nannual interest rate, term, and residual percent. Use whenever the user asks for \nmonthly cost, total credit cost, or loan breakdown.\n```\n\n---\n\n## Top Errors and Fixes\n\n### Error 1: `\"There was an error: 'Cannot assign to read only property \\\"name\\\" of object: Error: No execution data available'\"`\n\n**Cause**: you called `$fromAI()` inside the Code Tool sandbox.\n\n**Fix**: `$fromAI()` is a helper for **other** tool-enabled nodes (HTTP Request Tool, SendGrid Tool, `toolWorkflow`, etc.) — it's not exposed inside `toolCode`. Read the AI's input from `query` directly (or use `specifyInputSchema` for structured fields).\n\n### Error 2: `\"Wrong output type returned\"`\n\n**Cause**: you returned a workflow-style array like `[{ json: { ... } }]`. That's the Code **node** contract, not the Code **Tool** contract.\n\n**Fix**: return a string. For structured data, `return JSON.stringify(output)`.\n\n### Error 3: `\"The response property should be a string, but it is an object\"`\n\n**Cause**: you returned a plain object or array.\n\n**Fix**: `JSON.stringify()` the result, or coerce to a string.\n\n### Error 4: AI never calls the tool\n\n**Cause**: tool name is generic (`Code Tool`, `My Tool`) or description doesn't clearly state when to use it.\n\n**Fix**: rename to a verb-y name (`calculate_car_loan`), and rewrite the description to explicitly state the trigger conditions (e.g. \"Use this whenever the user asks about monthly cost\").\n\n### Error 5: AI sends garbage into `query`\n\n**Cause**: unstructured tool with a vague description. The LLM guesses at the format.\n\n**Fix**: either (a) include a concrete JSON example in the description, or (b) switch to `specifyInputSchema: true` so the LLM gets a typed schema.\n\n**See**: [ERROR_PATTERNS.md](ERROR_PATTERNS.md) for full catalog with reproductions.\n\n---\n\n## What's NOT Available in the Sandbox\n\nThe Code Tool sandbox is **narrower** than the Code node sandbox. Don't assume helpers carry over:\n\n| Helper | Code node | Code Tool |\n|---|---|---|\n| `$input.all()`, `$input.first()`, `$input.item` | ✅ | ❌ |\n| `$node[\"NodeName\"]` | ✅ | ❌ |\n| `$json`, `$binary` | ✅ | ❌ |\n| `$fromAI()` | ❌ | ❌ (despite sitting next to an AI agent) |\n| `this.helpers.httpRequest()` | ✅ | ❌ |\n| `DateTime` (Luxon) | ✅ | ✅ (standard in JS sandbox) |\n| `$jmespath()` | ✅ | ❌ |\n| `this.getContext(...)` | ✅ | ❌ |\n| `$getWorkflowStaticData(...)` | ✅ | ❌ |\n\n**Implication**: the Code Tool is for **pure computation**. If you need an HTTP call, an API lookup, or cross-invocation state, use a different tool node:\n- HTTP Request Tool for external API calls\n- `toolWorkflow` (Call Sub-workflow Tool) for multi-step logic with access to the full Code node sandbox\n- MCP \u002F database tools for persistent state\n\n---\n\n## When to Use Code Tool vs Alternatives\n\nUse **Code Tool** when:\n- ✅ Pure deterministic computation (math, parsing, formatting, validation)\n- ✅ Lightweight transformations the LLM shouldn't do itself (precision math, regex)\n- ✅ You want the code inline in the workflow, not in a separate sub-workflow\n\nUse **`toolWorkflow`** (Call Sub-workflow Tool) when:\n- ✅ You need multiple parameters with clean `$fromAI()` typing\n- ✅ You need access to `this.helpers`, credentials, or other nodes\n- ✅ Logic is reusable across agents\n- ✅ You want structured typed inputs WITHOUT writing a JSON Schema\n\nUse **HTTP Request Tool** when:\n- ✅ The tool is fundamentally a single API call\n- ✅ You want per-parameter `$fromAI()` bindings in URL\u002Fquery\u002Fbody\n\n**Rule of thumb**: if you find yourself wanting `$fromAI()`, you probably want `toolWorkflow` instead of `toolCode`.\n\n---\n\n## Complete Working Example\n\nA production calculator tool (unstructured, JSON-in-string pattern):\n\n```json\n{\n  \"parameters\": {\n    \"name\": \"calculate_car_loan\",\n    \"description\": \"Computes monthly car-loan payment using an annuity formula with residual\u002Fballoon. Call with a single JSON string. Example: {\\\"price\\\":439900,\\\"down_payment\\\":87980,\\\"interest_rate\\\":6.95,\\\"months\\\":36,\\\"residual_percent\\\":50,\\\"setup_fee\\\":695,\\\"monthly_admin_fee\\\":59}. Required: price, down_payment, interest_rate, months, residual_percent. Optional: setup_fee, monthly_admin_fee (default 0).\",\n    \"language\": \"javaScript\",\n    \"jsCode\": \"let params;\\ntry {\\n  params = typeof query === 'string' ? JSON.parse(query) : query;\\n} catch (e) {\\n  throw new Error('Invalid JSON: ' + e.message);\\n}\\n\\nconst price           = Number(params.price);\\nconst down_payment    = Number(params.down_payment);\\nconst interest_rate   = Number(params.interest_rate);\\nconst months          = Number(params.months);\\nconst residual_percent= Number(params.residual_percent);\\nconst setup_fee       = Number(params.setup_fee ?? 0) || 0;\\nconst monthly_admin_fee = Number(params.monthly_admin_fee ?? 0) || 0;\\n\\nif (!isFinite(price) || price \u003C= 0) throw new Error('price must be > 0');\\nif (down_payment \u003C 0 || down_payment >= price) throw new Error('down_payment must be in [0, price)');\\n\\nconst principal = price - down_payment;\\nconst residual  = price * (residual_percent \u002F 100);\\nconst r = interest_rate \u002F 100 \u002F 12;\\nconst growth = Math.pow(1 + r, months);\\nconst base = r === 0\\n  ? (principal - residual) \u002F months\\n  : (principal - residual \u002F growth) * r \u002F (1 - 1 \u002F growth);\\nconst monthly_payment = base + monthly_admin_fee;\\n\\nreturn JSON.stringify({\\n  monthly_payment_sek: Math.round(monthly_payment),\\n  loan_amount: Math.round(principal),\\n  residual_value_sek: Math.round(residual),\\n  total_cost_of_credit: Math.round(monthly_payment * months + residual + setup_fee - principal)\\n});\"\n  },\n  \"type\": \"@n8n\u002Fn8n-nodes-langchain.toolCode\",\n  \"typeVersion\": 1.3,\n  \"name\": \"calculate_car_loan\"\n}\n```\n\nWire it into an AI Agent via the `ai_tool` connection type.\n\n---\n\n## Integration with Other Skills\n\n**n8n-code-javascript**: the Code **node** skill. Most JavaScript patterns (arrays, map\u002Ffilter, DateTime) transfer — but I\u002FO contract is different. Don't copy data-access code.\n\n**n8n-node-configuration**: `specifyInputSchema` is a classic displayOptions-driven conditional field. Use `get_node({detail: \"standard\"})` on `@n8n\u002Fn8n-nodes-langchain.toolCode` to see schema-related properties.\n\n**n8n-workflow-patterns**: Code Tool sits inside the \"AI Agent with tools\" pattern. An agent typically has several tools; Code Tool is the \"local compute\" option.\n\n**n8n-validation-expert**: the three Code Tool errors listed above have clear signatures — if validation surfaces \"Wrong output type returned\", you know to switch from array-of-items to a string.\n\n---\n\n## Quick Reference Checklist\n\nBefore deploying a Code Tool:\n\n- [ ] **Node type** is `@n8n\u002Fn8n-nodes-langchain.toolCode` (not `nodes-base.code`)\n- [ ] **Tool name** is descriptive, verb-y, snake_case (e.g. `calculate_car_loan`)\n- [ ] **Description** states when to use the tool and (if unstructured) shows a JSON example\n- [ ] **Input** read from `query` (JS) or `_query` (Python)\n- [ ] **No `$fromAI()`** in the code body\n- [ ] **No `$input` \u002F `$json` \u002F `$helpers`** — those aren't in the sandbox\n- [ ] **Return** is a string (use `JSON.stringify()` for structured output)\n- [ ] **Wired** into an AI Agent via `ai_tool` connection\n- [ ] **Tested** with the exact kind of input the LLM will send (JSON in a string, or schema-validated object)\n\n---\n\n## Additional Resources\n\n- [INPUT_SCHEMA.md](INPUT_SCHEMA.md) — structured input (DynamicStructuredTool) in depth\n- [ERROR_PATTERNS.md](ERROR_PATTERNS.md) — full error catalog with causes and fixes\n\n### Official sources\n- [n8n Custom Code Tool docs](https:\u002F\u002Fdocs.n8n.io\u002Fintegrations\u002Fbuiltin\u002Fcluster-nodes\u002Fsub-nodes\u002Fn8n-nodes-langchain.toolcode\u002F)\n- [ToolCode source](https:\u002F\u002Fgithub.com\u002Fn8n-io\u002Fn8n\u002Fblob\u002Fmaster\u002Fpackages\u002F%40n8n\u002Fnodes-langchain\u002Fnodes\u002Ftools\u002FToolCode\u002FToolCode.node.ts) — the sandbox contract\n- [LangChain tool docs](https:\u002F\u002Fjs.langchain.com\u002Fdocs\u002Fmodules\u002Fagents\u002Ftools\u002F) — DynamicTool \u002F DynamicStructuredTool\n\n---\n\n**Remember**: the Code Tool is a LangChain tool wearing a Code-node UI. Contract is: **string in, string out**. Everything else follows from that.\n",{},"master","8ec37df6d71fb664ea19d32c079e7d3ff931a8e0","skills\u002Fintegrations\u002Fn8n-workflows\u002Fn8n-code-tool",3,"https:\u002F\u002Fgithub.com\u002FS3YED\u002Fappie-kit","https:\u002F\u002Fweblyfe.ai","https:\u002F\u002Fgithub.com\u002FS3YED","2026-08-27 01:54:02",{"source":7,"skillName":5,"commands":45,"prompt":55,"zipAvailable":56},[46,49,52],{"tool":47,"command":48},"npx","npx skills add S3YED\u002Fappie-kit --skill n8n-code-tool",{"tool":50,"command":51},"bunx","bunx skills add S3YED\u002Fappie-kit --skill n8n-code-tool",{"tool":53,"command":54},"pnpm","pnpm dlx skills add S3YED\u002Fappie-kit --skill n8n-code-tool","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FS3YED\u002Fappie-kit\u002Fblob\u002Fmaster\u002Fskills\u002Fintegrations\u002Fn8n-workflows\u002Fn8n-code-tool\u002FSKILL.md",true,[58,64,68],{"path":59,"resourceType":60,"resourceTypeDesc":61,"sizeBytes":62,"sourceHtmlUrl":63},"ERROR_PATTERNS.md","REFERENCE","参考文档",6832,"https:\u002F\u002Fgithub.com\u002FS3YED\u002Fappie-kit\u002Fblob\u002Fmaster\u002Fskills\u002Fintegrations\u002Fn8n-workflows\u002Fn8n-code-tool\u002FERROR_PATTERNS.md",{"path":65,"resourceType":60,"resourceTypeDesc":61,"sizeBytes":66,"sourceHtmlUrl":67},"INPUT_SCHEMA.md",6360,"https:\u002F\u002Fgithub.com\u002FS3YED\u002Fappie-kit\u002Fblob\u002Fmaster\u002Fskills\u002Fintegrations\u002Fn8n-workflows\u002Fn8n-code-tool\u002FINPUT_SCHEMA.md",{"path":69,"resourceType":60,"resourceTypeDesc":61,"sizeBytes":70,"sourceHtmlUrl":71},"README.md",6922,"https:\u002F\u002Fgithub.com\u002FS3YED\u002Fappie-kit\u002Fblob\u002Fmaster\u002Fskills\u002Fintegrations\u002Fn8n-workflows\u002Fn8n-code-tool\u002FREADME.md",[73,105,138,164,195,219],{"skillNo":74,"name":75,"nameZh":6,"description":76,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":6,"repositoryNo":11,"starsCount":12,"licenseSpdxId":13,"licenseFileUrl":6,"sourceHtmlUrl":77,"categories":78,"keywords":86,"publishedAt":31},"01M6JFD4M6N4DSGC7TXEJ5R3J2","ai-music","AI music generation and audio tools: HeartMuLa lyrics-to-music generation, songwriting craft (+ Suno prompts), and audio spectrogram\u002Ffeature visualization.","https:\u002F\u002Fgithub.com\u002FS3YED\u002Fappie-kit\u002Fblob\u002Fmaster\u002Fskills\u002Fwethlete\u002Fai-music\u002FSKILL.md",[79,82,85],{"categoryNo":80,"categoryName":81,"taxonomyType":19,"taxonomyTypeDesc":20},"01JBSEEDCAT000000000000013","分析与可视化",{"categoryNo":83,"categoryName":84,"taxonomyType":19,"taxonomyTypeDesc":20},"01JBSEEDCAT000000000000016","图像与多媒体",{"categoryNo":17,"categoryName":18,"taxonomyType":19,"taxonomyTypeDesc":20},[87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104],"music","ai music","humanizer","visualization","Tools","Audio","hermes","hermes agent","songwriting","suno","lyrics","prompts","heartmula","craft","generation","feature","ai music generation","music generation",{"skillNo":106,"name":107,"nameZh":6,"description":108,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":6,"repositoryNo":11,"starsCount":12,"licenseSpdxId":13,"licenseFileUrl":6,"sourceHtmlUrl":109,"categories":110,"keywords":117,"publishedAt":31},"01M6JFCZE4XNFQFMNZDHKHT5V5","agentic-webdesign-design-system-ingestion","Use v0 Design Systems 2.0, Bolt Design System Agents, or Lovable to generate production UI from a client's real design system components — not generic Tailwind. Use when building a client website where brand consistency matters.","https:\u002F\u002Fgithub.com\u002FS3YED\u002Fappie-kit\u002Fblob\u002Fmaster\u002Fskills\u002Fweb-design\u002Fagentic-webdesign-design-system-ingestion\u002FSKILL.md",[111,114],{"categoryNo":112,"categoryName":113,"taxonomyType":19,"taxonomyTypeDesc":20},"01JBSEEDCAT000000000000015","视觉设计",{"categoryNo":115,"categoryName":116,"taxonomyType":24,"taxonomyTypeDesc":25},"01JBSEEDCAT000000000000032","设计师",[118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137],"design","agentic","design system","system","ingestion","webdesign","agentic webdesign design system ingestion","components","generate","design systems","website","ui","Tailwind","bolt","lovable","v0","design-system","wed","design system components","appie",{"skillNo":139,"name":140,"nameZh":6,"description":141,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":6,"repositoryNo":11,"starsCount":12,"licenseSpdxId":13,"licenseFileUrl":6,"sourceHtmlUrl":142,"categories":143,"keywords":146,"publishedAt":31},"01M6JFCVPX3913CFAS6QQJ33ZB","agentic-webdesign-agent-elements","Use 21st.dev Agent Elements — 25 shadcn\u002Fui components purpose-built for AI agent UIs. Tool cards (Bash, Edit, Search, Plan, Subagent, MCP), chat, input, streaming. Open source, shadcn-registry install, no runtime lock-in.","https:\u002F\u002Fgithub.com\u002FS3YED\u002Fappie-kit\u002Fblob\u002Fmaster\u002Fskills\u002Fweb-design\u002Fagentic-webdesign-agent-elements\u002FSKILL.md",[144,145],{"categoryNo":17,"categoryName":18,"taxonomyType":19,"taxonomyTypeDesc":20},{"categoryNo":115,"categoryName":116,"taxonomyType":24,"taxonomyTypeDesc":25},[119,147,123,148,149,150,125,151,152,153,154,155,156,157,158,159,160,161,162,163],"elements","agentic webdesign agent elements","MCP","ai agent","registry","search","streaming","open source","open","Bash","plan","subagent","edit","install","input","lock","source",{"skillNo":165,"name":166,"nameZh":6,"description":167,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":6,"repositoryNo":11,"starsCount":12,"licenseSpdxId":13,"licenseFileUrl":6,"sourceHtmlUrl":168,"categories":169,"keywords":174,"publishedAt":31},"01M6JFCQC7H65M9QJ6TRE71BS1","vercel-deployment","Deploy static sites and frontends to Vercel — handles both CLI and REST API paths, including the CLI token sanitization workaround.","https:\u002F\u002Fgithub.com\u002FS3YED\u002Fappie-kit\u002Fblob\u002Fmaster\u002Fskills\u002Fsoftware-development\u002Fvercel-deployment\u002FSKILL.md",[170,173],{"categoryNo":171,"categoryName":172,"taxonomyType":19,"taxonomyTypeDesc":20},"01JBSEEDCAT000000000000011","运维与部署",{"categoryNo":17,"categoryName":18,"taxonomyType":19,"taxonomyTypeDesc":20},[175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194],"deployment","vercel deployment","vercel","macos","cli","linux","windows","deploy","vercel deploy","REST","api","site","deploy to vercel","token","rest api","host","sites","paths","sanitization","static site",{"skillNo":196,"name":197,"nameZh":6,"description":198,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":6,"repositoryNo":11,"starsCount":12,"licenseSpdxId":13,"licenseFileUrl":6,"sourceHtmlUrl":199,"categories":200,"keywords":202,"publishedAt":31},"01M6JFCM4SMTXBM5A01BK2YQG1","software-quality-workflows","Umbrella workflow for TDD, debugging, code simplification, spikes, pre-commit review, and debugger-assisted investigation.","https:\u002F\u002Fgithub.com\u002FS3YED\u002Fappie-kit\u002Fblob\u002Fmaster\u002Fskills\u002Fsoftware-development\u002Fsoftware-quality-workflows\u002FSKILL.md",[201],{"categoryNo":17,"categoryName":18,"taxonomyType":19,"taxonomyTypeDesc":20},[203,204,205,206,207,208,209,210,211,27,212,213,214,215,216,217,218],"workflows","quality","software","software quality workflows","review","tdd","workflow","commit","debugging","debugger","pre-commit","investigation","code simplification","user","simplification","for",{"skillNo":220,"name":221,"nameZh":6,"description":222,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":6,"repositoryNo":11,"starsCount":12,"licenseSpdxId":13,"licenseFileUrl":6,"sourceHtmlUrl":223,"categories":224,"keywords":232,"publishedAt":31},"01M6JFCGD0M6CEATY01W7YN6DB","react-component-refactoring","Safely refactor large React components into smaller, maintainable pieces using proven patterns","https:\u002F\u002Fgithub.com\u002FS3YED\u002Fappie-kit\u002Fblob\u002Fmaster\u002Fskills\u002Fsoftware-development\u002Freact-component-refactoring\u002FSKILL.md",[225,228,231],{"categoryNo":226,"categoryName":227,"taxonomyType":19,"taxonomyTypeDesc":20},"01JBSEEDCAT000000000000007","代码审查",{"categoryNo":229,"categoryName":230,"taxonomyType":19,"taxonomyTypeDesc":20},"01JBSEEDCAT000000000000009","前端开发",{"categoryNo":17,"categoryName":18,"taxonomyType":19,"taxonomyTypeDesc":20},[233,234,235,236,237,238,239,240,178,241,242,125,243,181,244,27,245,246,247,248],"react","component","refactoring","component refactoring","react component","react component refactoring","frontend","writing","safe","typescript","react components","modular","refactor","simplify","patterns","test-driven-development"]