n8n-io/n8n · error · Error

Unable to convert tool to N8nTool: ${JSON.stringify(tool)}

Error message

Unable to convert tool to N8nTool: ${JSON.stringify(tool)}

What it means

The tool converter accepts a few known tool shapes (Anthropic-style, OpenAI function-calling `{type:'function', function:{...}}`, and a Zod/raw-schema variant handled earlier). Anything that doesn't match one of these discriminators cannot be turned into an N8nTool, so it throws with the serialized input for debugging. This guards the tool-adapter boundary against malformed provider output.

Source

Thrown at packages/@n8n/ai-utilities/src/converters/tool.ts:51

		const structuredTool = tool as LangchainTools.StructuredTool;
		return {
			type: 'function',
			name: structuredTool.name,
			description: structuredTool.description,
			inputSchema: structuredTool.schema as JSONSchema7 | ZodTypeAny,
		};
	}
	if ('function' in tool && 'type' in tool && tool.type === 'function') {
		const functionTool = tool.function as FunctionDefinition;
		return {
			type: 'function',
			name: functionTool.name,
			description: functionTool.description,
			inputSchema: functionTool.parameters as JSONSchema7,
		};
	}

	throw new Error(`Unable to convert tool to N8nTool: ${JSON.stringify(tool)}`);
}

export function getParametersJsonSchema(tool: N8nTools.FunctionTool): JSONSchema7 {
	const schema = tool.inputSchema;
	if (schema instanceof ZodSchema) {
		if ('toJSONSchema' in schema && typeof schema.toJSONSchema === 'function') {
			return schema.toJSONSchema();
		}
		return zodToJsonSchema(schema) as JSONSchema7;
	}
	return schema;
}

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Construct tools with the OpenAI shape { type:'function', function:{ name, description, parameters } } or the Anthropic shape the converter expects.
  2. Inspect the serialized tool in the error and add a branch if it's a legitimate new shape.
  3. Validate tool objects at the boundary with a schema before passing them in.

Example fix

// before
{ name: 'foo', description: '...', parameters: {...} }

// after
{ type: 'function', function: { name: 'foo', description: '...', parameters: {...} } }
Defensive patterns

Strategy: type-guard

Validate before calling

function isKnownToolShape(t: unknown): boolean {
  return (
    typeof t === 'object' && t !== null && (
      ('type' in t && (t as { type: string }).type === 'function' && 'function' in t) ||
      ('name' in t && 'inputSchema' in t)
    )
  );
}
if (!isKnownToolShape(tool)) throw new Error('unsupported tool shape');

Type guard

function isOpenAiFunctionTool(t: unknown): t is { type: 'function'; function: { name: string; description?: string; parameters: object } } {
  return typeof t === 'object' && t !== null && 'type' in t && (t as { type: string }).type === 'function' && 'function' in t;
}

Prevention

When it happens

Trigger: Passing a tool object missing the `function`/`type:'function'` discriminator or the Anthropic fields; a tool shape from a provider format the converter doesn't support; a hand-built object that loosely resembles a tool but lacks required keys.

Common situations: A provider returns a non-standard tool descriptor; version skew in provider SDKs changes the tool schema; downstream code forwards an unvalidated object as a tool.

Related errors


AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12). Data as JSON: /api/errors/4c363f64cb668a86. Report an issue: GitHub.