📦 deps(thirdparty): update snapshots

This commit is contained in:
ci[bot]
2026-07-22 10:09:47 +00:00
parent 316c012df0
commit 60364c6660
353 changed files with 24740 additions and 1264 deletions
@@ -0,0 +1,178 @@
# Code Tool Error Patterns
The most common failure modes for `@n8n/n8n-nodes-langchain.toolCode`, with exact error strings, root causes, and fixes.
---
## Error 1: `"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](INPUT_SCHEMA.md)).
```javascript
// ❌ 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;
```
---
## Error 2: `"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:
```javascript
// ❌ Broken
return [{ json: { monthly_payment: 5405 } }];
// ✅ Fixed
return JSON.stringify({ monthly_payment: 5405 });
```
---
## Error 3: `"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:
```javascript
return 42; // ✅ becomes "42"
```
**Booleans are NOT auto-converted** — stringify explicitly:
```javascript
return String(someBoolean); // ✅
return JSON.stringify(someBoolean); // ✅
```
---
## Error 4: AI never calls the tool
**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**:
1. **Generic name**. Default names like `Code Tool` or `My Tool` give the LLM no signal.
- Fix: rename to verb-y, domain-specific snake_case: `calculate_car_loan`, `search_orders`, `lookup_customer`.
2. **Description doesn't state the trigger**. "Calculates things" is too vague.
- Fix: explicitly list the user intents that should invoke the tool. `"Use this whenever the user asks about monthly cost, loan breakdown, or total interest."`
3. **Tool isn't wired**. The node sits in the canvas but isn't connected to the AI Agent's `ai_tool` input.
- Fix: connect it. Check the workflow JSON `connections` block has `"<tool_name>": { "ai_tool": [[{ "node": "AI Agent", "type": "ai_tool", "index": 0 }]] }`.
4. **Name violates `[A-Za-z0-9_]+`**. Spaces, hyphens, and emoji in the tool name cause silent skip on v1.1+.
- Fix: rename to `snake_case_only`.
---
## Error 5: LLM sends malformed `query`
**Symptom**: your `JSON.parse(query)` throws, or fields come through as wrong types.
**Causes**:
- You're in unstructured mode and the description is ambiguous, so the LLM invents a format.
- You asked for a JSON string but the LLM sent a natural-language sentence.
- Numeric fields arrive as strings because the LLM serialized them that way.
**Fixes**, in order of preference:
1. **Switch to structured mode**. Set `specifyInputSchema: true` and define fields. The LLM now gets a typed schema and n8n validates before your code runs.
2. **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}
```
3. **Coerce defensively**:
```javascript
const params = JSON.parse(query);
const price = Number(params.price);
if (!isFinite(price)) throw new Error('price must be numeric');
```
---
## Error 6: `"$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**:
- Pure computation? Stay in Code Tool, use plain JS.
- Need HTTP? Move to **HTTP Request Tool** (with `$fromAI()` in URL/body).
- Need other-node data or credentials? Move to **Call Sub-workflow Tool (`toolWorkflow`)** — its sub-workflow has a full Code node sandbox.
- Need state across calls? Not possible in Code Tool. Use a sub-workflow that reads/writes a Data Table, Redis, etc.
---
## Error 7: Python-specific — `"name 'query' is not defined"`
**Cause**: in Python, the input variable is `_query` (underscore prefix), not `query`.
```python
# ❌ Broken
result = process(query)
# ✅ Fixed
result = process(_query)
```
---
## Error Prevention Checklist
Before saving a Code Tool:
- [ ] Tool **name** is snake_case, descriptive, and unique
- [ ] **Description** tells the LLM when to call it, with an example if unstructured
- [ ] **No `$fromAI()`** in the code body
- [ ] **No `$input`, `$json`, `$helpers`** — not in this sandbox
- [ ] Input read from `query` (JS) or `_query` (Python)
- [ ] All code paths `return` a string (or a number that auto-converts)
- [ ] If returning structured data, wrapped in `JSON.stringify(...)`
- [ ] Wired to an AI Agent via `ai_tool` connection
- [ ] For multi-field input: either example JSON in description, or `specifyInputSchema: true`
---
## Debugging tips
- **Use the Execution view**, not just the test output. The agent's tool invocation and raw input/output are visible there — you can see exactly what `query` the LLM sent.
- **Log inside the tool** by including fields in the returned JSON:
```javascript
return JSON.stringify({ received_query: query, result: /* ... */ });
```
The LLM sees the echo, and you can spot malformed input.
- **Test the tool without the LLM** by temporarily turning the tool node into a standalone Code node with hard-coded `query`, running it manually, then swapping back.
@@ -0,0 +1,132 @@
# Input Schema for Code Tool (Structured Mode)
How to turn `@n8n/n8n-nodes-langchain.toolCode` into a **DynamicStructuredTool** so the LLM passes typed arguments instead of a free-form string.
---
## Why use a schema?
Without a schema, the Code Tool is a LangChain `DynamicTool`:
- LLM sees: "one string argument called query"
- You must parse whatever the LLM sends
- Typos, missing fields, wrong types are your problem at runtime
With a schema, the Code Tool becomes a `DynamicStructuredTool`:
- LLM sees: a typed object with named fields and descriptions
- Runtime rejects invalid calls before your code runs
- Numeric fields stay numeric (no more `Number(params.price)` for every field)
- Tool calls are more reliable — most modern LLMs handle structured tools better than "here's a JSON string please"
**Cost**: a little config to define the schema, and the node must be on a version that supports it.
---
## Enabling the schema
Set `specifyInputSchema: true` on the `toolCode` parameters. Two schema-definition styles:
### Style A: `fromJson` — paste a representative example (v≥1.3, recommended)
The easiest. Give n8n an example JSON, and it infers the schema for you.
```json
{
"parameters": {
"name": "calculate_car_loan",
"description": "Computes monthly car-loan payment using an annuity formula with optional balloon.",
"language": "javaScript",
"specifyInputSchema": true,
"schemaType": "fromJson",
"jsonSchemaExample": "{\n \"price\": 439900,\n \"down_payment\": 87980,\n \"interest_rate\": 6.95,\n \"months\": 36,\n \"residual_percent\": 50,\n \"setup_fee\": 695,\n \"monthly_admin_fee\": 59\n}",
"jsCode": "// query is now a validated OBJECT, not a string\nconst { price, down_payment, interest_rate, months, residual_percent, setup_fee = 0, monthly_admin_fee = 0 } = query;\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});"
},
"type": "@n8n/n8n-nodes-langchain.toolCode",
"typeVersion": 1.3,
"name": "calculate_car_loan"
}
```
**How it works**: n8n looks at the example, infers `{price: number, down_payment: number, ...}`, and generates a JSON Schema. The LLM sees that schema and passes a validated object.
### Style B: `manual` — write the JSON Schema yourself
Use when you need descriptions per field, enums, min/max constraints, or optional fields.
```json
{
"parameters": {
"name": "calculate_car_loan",
"description": "Computes monthly car-loan payment.",
"language": "javaScript",
"specifyInputSchema": true,
"schemaType": "manual",
"inputSchema": "{\n \"type\": \"object\",\n \"required\": [\"price\", \"down_payment\", \"interest_rate\", \"months\", \"residual_percent\"],\n \"properties\": {\n \"price\": { \"type\": \"number\", \"description\": \"Car price in SEK\" },\n \"down_payment\": { \"type\": \"number\", \"description\": \"Down payment in SEK\" },\n \"interest_rate\": { \"type\": \"number\", \"description\": \"Annual nominal rate in percent, e.g. 6.95\" },\n \"months\": { \"type\": \"integer\", \"minimum\": 1, \"description\": \"Loan term in months\" },\n \"residual_percent\": { \"type\": \"number\", \"minimum\": 0, \"maximum\": 99, \"description\": \"Balloon as % of price\" },\n \"setup_fee\": { \"type\": \"number\", \"default\": 0 },\n \"monthly_admin_fee\": { \"type\": \"number\", \"default\": 0 }\n }\n}",
"jsCode": "const { price, down_payment, interest_rate, months, residual_percent, setup_fee = 0, monthly_admin_fee = 0 } = query;\n// ... same computation as above ...\nreturn JSON.stringify({ monthly_payment_sek: /*...*/ });"
},
"type": "@n8n/n8n-nodes-langchain.toolCode",
"typeVersion": 1.3,
"name": "calculate_car_loan"
}
```
**When `manual` is worth it**:
- You want per-field `description` strings (the LLM reads these)
- You need `enum` values (e.g. currency: `["SEK", "EUR", "USD"]`)
- You need numeric constraints (`minimum`, `maximum`)
- You want to mark fields as optional cleanly
---
## How `query` behaves with a schema
Source of truth from the ToolCode sandbox:
```typescript
const sandbox = new JsTaskRunnerSandbox(workflowMode, ctx, undefined, { query });
```
The sandbox always receives `{ query }`. The difference is what `query` holds:
| Mode | Type of `query` | How to use |
|---|---|---|
| No schema | `string` | `JSON.parse(query)` if you want structure |
| With schema | `object` (validated) | Destructure: `const { price, months } = query;` |
In Python, the same applies — `_query` is a string without schema, a dict with schema.
---
## Schema version compatibility
- `specifyInputSchema` and `schemaType: "manual"` with `inputSchema`: available in v1.2
- `schemaType: "fromJson"` with `jsonSchemaExample`: requires v≥1.3
Set `typeVersion: 1.3` on the node if you want `fromJson`. Older installs should use `manual`.
---
## Picking a pattern
```
Does your tool need more than one input field?
├─ No (just a URL, question, text blob)
│ └─ Unstructured — skip the schema
├─ Yes, and fields are all typed (numbers, bools, enums)
│ └─ Structured with fromJson (easiest)
├─ Yes, and you need constraints or rich descriptions
│ └─ Structured with manual
└─ Yes, and fields are complex / reusable across agents
└─ Use toolWorkflow (sub-workflow tool) instead of toolCode
```
---
## Gotcha: schema must be valid JSON
`jsonSchemaExample` and `inputSchema` are **strings containing JSON**, not objects. Watch the escaping when you paste them into workflow JSON. If the node won't save or the LLM doesn't see the fields, validate the JSON separately first.
---
## Gotcha: schema changes don't retroactively fix old agent runs
If an agent was already started with an unstructured tool and you flip it to structured, the agent's system prompt may still reflect the old contract until it's reloaded. Force a re-run / re-open the agent node after changing schema settings.