本文へ移動
cccskills
無料GitHub で公開

n8n-code-tool

Write JavaScript or Python for the n8n Custom Code Tool (@n8n/n8n-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`/`$input`/`$helpers` in the Code Tool sandbox, naming rules for AI invocation, and when to use `toolWorkflow`/HTTP Request Tool instead.

インストール方法を見る

含まれるファイル(4)

  • SKILL.md15.9 KB
  • ERROR_PATTERNS.md6.7 KB
  • INPUT_SCHEMA.md6.2 KB
  • README.md6.8 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

n8n Custom Code Tool

Expert guidance for writing code inside @n8n/n8n-nodes-langchain.toolCode — the tool an AI Agent can invoke, not the regular workflow Code node.


⚠️ This is NOT the Code node

The 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.

Code nodeCustom Code Tool
Node typen8n-nodes-base.code@n8n/n8n-nodes-langchain.toolCode
Packagen8n-nodes-base@n8n/n8n-nodes-langchain
Invoked byPrevious node (workflow flow)AI Agent (LangChain)
Input$input.all() — item streamquery — string or object from LLM
Return[{json: {...}}] (items array)A string
$fromAI()N/ANot available (see Errors)
HTTP helperthis.helpers.httpRequest (auth helpers blocked)Not exposed to the tool sandbox
StatePer-run execution dataNo getContext, no $getWorkflowStaticData

If you treat it like a Code node, it fails. The rest of this skill covers the Code Tool's actual contract.


Quick Start

Minimal JavaScript Code Tool

// `query` is whatever the AI sent (a string by default)
return `You asked: ${query}`;

Minimal Python Code Tool

# `_query` is whatever the AI sent (a string by default)
return f"You asked: {_query}"

Essential Rules

  1. Return a string. Numbers are auto-converted. Anything else throws "The response property should be a string, but it is an object".
  2. Input variable is fixed: query (JS), _query (Python). You cannot rename it.
  3. Do NOT use $fromAI() inside the Code Tool sandbox — it throws "No execution data available".
  4. Do NOT use [{json: {...}}] return format — that's for Code nodes. Throws "Wrong output type returned".
  5. Use a descriptive tool name (letters/numbers/underscores, v1.1+). The agent calls the tool by its name.
  6. Write a precise description — the LLM decides whether to invoke the tool based on it.

The Two Input Modes

The Code Tool has two input shapes, controlled by specifyInputSchema:

Mode 1: Unstructured (default, specifyInputSchema: false)

The 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.

// Parse a JSON string the AI sent
let params;
try {
  params = typeof query === 'string' ? JSON.parse(query) : query;
} catch (e) {
  throw new Error('Expected a JSON object. Parser said: ' + e.message);
}
const price = Number(params.price);
const months = Number(params.months);
// ...
return JSON.stringify({ monthly_payment: /* ... */ });

Pros: simplest to set up, one field to describe. Cons: no schema validation — if the LLM forgets a field, the tool throws at runtime.

Best for: quick prototypes, tools with one natural input (a question, a URL, a text blob).

Mode 2: Structured (specifyInputSchema: true)

The tool becomes a LangChain DynamicStructuredTool. The LLM sees a typed argument schema and passes a validated object as query. You access fields directly.

// query is now an object matching your schema
const price = query.price;
const months = query.months;
const residual_percent = query.residual_percent;

const monthly = computeAnnuity(price, months, residual_percent);
return JSON.stringify({ monthly_payment: monthly });

Schema is defined via either:

  • schemaType: "fromJson" + jsonSchemaExample (n8n v≥1.3) — paste an example JSON, n8n infers the schema
  • schemaType: "manual" + inputSchema — write a full JSON Schema yourself

Pros: LLM gets type hints, invalid calls rejected before your code runs, cleaner code. Cons: a little more setup; requires n8n version with schema support.

Best for: production tools with multiple typed parameters (calculators, API wrappers, anything with numeric fields the LLM tends to stringify).

See: INPUT_SCHEMA.md for complete schema setup.


Return Format

The return value must be a string. The LLM reads it as the tool's observation.

// ✅ String
return "42";

// ✅ Number (auto-converted to string by n8n)
return 42;

// ✅ JSON-encoded structured result (recommended for rich output)
return JSON.stringify({ result: 42, currency: "SEK" });

// ❌ Raw object → "The response property should be a string, but it is an object"
return { result: 42 };

// ❌ Workflow item format → "Wrong output type returned"
return [{ json: { result: 42 } }];

// ❌ Array → "The response property should be a string, but it is an object"
return [1, 2, 3];

Best practice: JSON-stringify structured results

When your tool has more than a trivial scalar output, return a JSON string:

return JSON.stringify({
  monthly_payment_sek: 5405,
  loan_amount: 351920,
  total_cost_of_credit: 63295
});

The LLM parses JSON reliably and can pick the fields it needs to present to the user.

Error handling: the agent reads your failures

Errors don't just stop the workflow — they go back to the LLM, which usually corrects its call and retries. Use that:

// Option A: throw — n8n surfaces the message to the agent
if (!isFinite(price)) throw new Error('price must be a number, e.g. 439900');

// Option B: return an error string — agent reads it like any tool result
if (!isFinite(price)) return JSON.stringify({ error: 'price must be a number, e.g. 439900' });

Either 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.


Tool Name and Description

These fields are NOT documentation — they are the tool contract the LLM sees. Treat them as prompt engineering.

Name

  • Must match [A-Za-z0-9_]+ (v1.1+). No spaces, no hyphens, no emoji.
  • Use a verb-y descriptive name: calculate_car_loan, get_weather, search_orders.
  • The agent calls the tool by this name. Code Tool (the default) is useless — the agent won't know when to call it.

Description

  • Explain when to use it and what to send.
  • If unstructured mode, include an example of the JSON string the LLM should send.
  • If structured mode, the schema speaks for itself — just describe purpose.

Unstructured example (JSON-in-string pattern):

Deterministiskt beräknar månadskostnad för billån. Anropa med EN JSON-sträng:
{"price":439900,"down_payment":87980,"interest_rate":6.95,"months":36,"residual_percent":50}
Fält: price (SEK), down_payment (SEK), interest_rate (% per år), months, residual_percent (0-99).

Structured example (schema-defined):

Deterministically computes the monthly car-loan payment given price, down payment, 
annual interest rate, term, and residual percent. Use whenever the user asks for 
monthly cost, total credit cost, or loan breakdown.

Top Errors and Fixes

Error 1: "There was an error: 'Cannot assign to read only property \"name\" of object: Error: No execution data available'"

Cause: you called $fromAI() inside the Code Tool sandbox.

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).

Error 2: "Wrong output type returned"

Cause: you returned a workflow-style array like [{ json: { ... } }]. That's the Code node contract, not the Code Tool contract.

Fix: return a string. For structured data, return JSON.stringify(output).

Error 3: "The response property should be a string, but it is an object"

Cause: you returned a plain object or array.

Fix: JSON.stringify() the result, or coerce to a string.

Error 4: AI never calls the tool

Cause: tool name is generic (Code Tool, My Tool) or description doesn't clearly state when to use it.

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").

Error 5: AI sends garbage into query

Cause: unstructured tool with a vague description. The LLM guesses at the format.

Fix: either (a) include a concrete JSON example in the description, or (b) switch to specifyInputSchema: true so the LLM gets a typed schema.

See: ERROR_PATTERNS.md for full catalog with reproductions.


What's NOT Available in the Sandbox

The Code Tool sandbox is narrower than the Code node sandbox. Don't assume helpers carry over:

HelperCode nodeCode Tool
$input.all(), $input.first(), $input.item✅❌
$node["NodeName"]✅❌
$json, $binary✅❌
$fromAI()❌❌ (despite sitting next to an AI agent)
this.helpers.httpRequest()✅❌
DateTime (Luxon)✅✅ (standard in JS sandbox)
$jmespath()✅❌
this.getContext(...)✅❌
$getWorkflowStaticData(...)✅❌

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:

  • HTTP Request Tool for external API calls
  • toolWorkflow (Call Sub-workflow Tool) for multi-step logic with access to the full Code node sandbox
  • MCP / database tools for persistent state

When to Use Code Tool vs Alternatives

Use Code Tool when:

  • ✅ Pure deterministic computation (math, parsing, formatting, validation)
  • ✅ Lightweight transformations the LLM shouldn't do itself (precision math, regex)
  • ✅ You want the code inline in the workflow, not in a separate sub-workflow

Use toolWorkflow (Call Sub-workflow Tool) when:

  • ✅ You need multiple parameters with clean $fromAI() typing
  • ✅ You need access to this.helpers, credentials, or other nodes
  • ✅ Logic is reusable across agents
  • ✅ You want structured typed inputs WITHOUT writing a JSON Schema

Use HTTP Request Tool when:

  • ✅ The tool is fundamentally a single API call
  • ✅ You want per-parameter $fromAI() bindings in URL/query/body

Rule of thumb: if you find yourself wanting $fromAI(), you probably want toolWorkflow instead of toolCode.


Complete Working Example

A production calculator tool (unstructured, JSON-in-string pattern):

{
  "parameters": {
    "name": "calculate_car_loan",
    "description": "Computes monthly car-loan payment using an annuity formula with residual/balloon. 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).",
    "language": "javaScript",
    "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 <= 0) throw new Error('price must be > 0');\nif (down_payment < 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 / 100);\nconst r = interest_rate / 100 / 12;\nconst growth = Math.pow(1 + r, months);\nconst base = r === 0\n  ? (principal - residual) / months\n  : (principal - residual / growth) * r / (1 - 1 / 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});"
  },
  "type": "@n8n/n8n-nodes-langchain.toolCode",
  "typeVersion": 1.3,
  "name": "calculate_car_loan"
}

Wire it into an AI Agent via the ai_tool connection type.


Integration with Other Skills

n8n-code-javascript: the Code node skill. Most JavaScript patterns (arrays, map/filter, DateTime) transfer — but I/O contract is different. Don't copy data-access code.

n8n-node-configuration: specifyInputSchema is a classic displayOptions-driven conditional field. Use get_node({detail: "standard"}) on @n8n/n8n-nodes-langchain.toolCode to see schema-related properties.

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.

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.


Quick Reference Checklist

Before deploying a Code Tool:

  • Node type is @n8n/n8n-nodes-langchain.toolCode (not nodes-base.code)
  • Tool name is descriptive, verb-y, snake_case (e.g. calculate_car_loan)
  • Description states when to use the tool and (if unstructured) shows a JSON example
  • Input read from query (JS) or _query (Python)
  • No $fromAI() in the code body
  • No $input / $json / $helpers — those aren't in the sandbox
  • Return is a string (use JSON.stringify() for structured output)
  • Wired into an AI Agent via ai_tool connection
  • Tested with the exact kind of input the LLM will send (JSON in a string, or schema-validated object)

Additional Resources

Official sources


Remember: the Code Tool is a LangChain tool wearing a Code-node UI. Contract is: string in, string out. Everything else follows from that.

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

Design n8n AI agents the right way. Use when building or editing any @n8n/n8n-nodes-langchain.* AI node — an AI Agent, LLM chain, Text Classifier, or Information Extractor — and whenever the user mentions AI agents, LLM with tools, tool calling, $fromAI, system prompts, agent memory, sessionId, structured/JSON output, output parser, RAG, vector store, a chat assistant/bot, or human-in-the-loop review. Covers Agent-vs-chain-vs-classifier choice, the model/memory/tools/outputParser slots, tool names/descriptions as prompt, structured output with autoFix, memory, RAG, human review, and chat topologies.

日本語の概要は準備中です。原文の説明を表示しています。

czlonkowski/n8n-skills6,4072026年10月9日 更新

Handle files and binary data in n8n correctly. Use when working with files, images, PDFs, attachments, uploads or downloads, base64, vision/multimodal input, or when an AI agent needs a file as tool input or output — and whenever the user mentions $binary, binaryPropertyName, "read the PDF", "attach the file", "send the image", Merge losing binary, or a CDN for chat images. Covers the $binary vs $json split, reading/writing binary, keeping binary alive across transforms with Merge, the agent-tool binary boundary, and the CDN/URL requirement for chat surfaces.

日本語の概要は準備中です。原文の説明を表示しています。

czlonkowski/n8n-skills6,4072026年10月9日 更新

Write JavaScript code in n8n Code nodes. Use when writing JavaScript in n8n, using $input/$json/$node syntax, making HTTP requests with this.helpers / the $helpers global, working with dates using DateTime, troubleshooting Code node errors, choosing between Code node modes, or doing any custom data transformation in n8n. Always use this skill when a workflow needs a Code node — whether for data aggregation, filtering, API calls, format conversion, batch processing logic, or any custom JavaScript. Covers SplitInBatches loop patterns, cross-iteration data, pairedItem, and real-world production patterns. Also use when asked why a Code node or workflow is slow, which execution mode is faster, or how to cut per-item overhead on large datasets. EXCEPTION — for the AI-agent-callable Custom Code Tool (@n8n/n8n-nodes-langchain.toolCode, a tool attached to an AI Agent), use the n8n-code-tool skill instead; it has a different runtime contract.

日本語の概要は準備中です。原文の説明を表示しています。

czlonkowski/n8n-skills6,4072026年10月9日 更新

Write Python in n8n Code nodes (native Python, `language` pythonNative, n8n 2.x). Use when the user explicitly wants Python in a Code node, when migrating old Pyodide/"Python (Beta)" code that used _input/_json/_node/_now, or when a Python Code node fails with NameError, "Security violations detected", "Import of standard library module … is disallowed", "__build_class__ not found", "A 'json' property isn't a dictionary", or "Python runner unavailable". Covers the only two variables (_items/_item), dict-only access, imports blocked by default, the sandbox's denied builtins, accepted return shapes, and how errors interact with onError. JavaScript is the default for Code nodes — native Python has no n8n helpers and, by default, no imports. EXCEPTION — for Python in the AI-agent-callable Custom Code Tool (@n8n/n8n-nodes-langchain.toolCode), use the n8n-code-tool skill instead (input is _query, return must be a string).

日本語の概要は準備中です。原文の説明を表示しています。

czlonkowski/n8n-skills6,4072026年10月9日 更新

Wire n8n error handling so failures are loud, structured, and recoverable. Use when building any webhook/API workflow, a scheduled or unattended workflow, or any path where a silent failure would drop user-visible work — and whenever the user mentions error handling, onError, continueErrorOutput, error branches/outputs, retries, retryOnFail, Respond to Webhook status codes, 4xx/5xx, Error Trigger, or "my workflow fails silently". Covers per-node error outputs and wiring, retry/self-healing, error-trigger workflows, and 4xx/5xx response shapes.

日本語の概要は準備中です。原文の説明を表示しています。

czlonkowski/n8n-skills6,4072026年10月9日 更新

Validate n8n expression syntax and fix common errors. Use when writing n8n expressions, using {{}} syntax, accessing $json/$node variables, troubleshooting expression errors, mapping data between nodes, or referencing webhook data in workflows. Use this skill whenever configuring node fields that reference data from previous nodes — expressions are how n8n passes data between nodes, and getting the syntax wrong is the most common source of workflow errors. Also use when asked whether a complex expression hurts performance.

日本語の概要は準備中です。原文の説明を表示しています。

czlonkowski/n8n-skills6,4072026年10月9日 更新

czlonkowski のスキルをすべて見る

このスキルの問題を報告する