n8n-io/n8n · error · Error

Tool name is required

Error message

Tool name is required

What it means

Tool.build() validates that the tool has a non-empty name. The Tool constructor takes a name string, but an empty string passes the constructor signature while failing this runtime check. Every BuiltTool needs a name so the agent loop, tool-call routing, and message serialization can identify it.

Source

Thrown at packages/@n8n/agents/src/sdk/tool.ts:358

	 * Set provider-specific options forwarded to the AI SDK's `tool()` call.
	 * Keyed by provider name (e.g. `anthropic`, `openai`).
	 *
	 * Example: `.providerOptions({ anthropic: { eagerInputStreaming: true } })`
	 */
	providerOptions(options: Record<string, JSONObject>): this {
		this.providerOptionsValue = { ...this.providerOptionsValue, ...options };
		return this;
	}

	/**
	 * Validate configuration and produce a `BuiltTool`.
	 *
	 * @throws if name, description, input schema, or handler is missing.
	 * @throws if suspend is declared without resume or vice versa.
	 */
	build(): BuiltTool {
		if (!this.name) {
			throw new Error('Tool name is required');
		}
		if (!this.desc) {
			throw new Error(`Tool "${this.name}" requires a description`);
		}
		if (!this.inputSchema) {
			throw new Error(`Tool "${this.name}" requires an input schema`);
		}
		if (!this.handlerFn) {
			throw new Error(`Tool "${this.name}" requires a handler`);
		}

		const hasSuspend = this.suspendSchemaValue !== undefined;
		const hasResume = this.resumeSchemaValue !== undefined;

		if (hasSuspend && !hasResume) {
			throw new Error(`Tool "${this.name}" has .suspend() but missing .resume()`);
		}
		if (hasResume && !hasSuspend) {

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Pass a non-empty, unique name to the Tool constructor: new Tool('search_docs').
  2. When building tools dynamically, validate the name source before construction and throw a clearer upstream error.
  3. Use sanitizeToolName-style naming if generating from external input to guarantee a non-empty result.

Example fix

// before
const tool = new Tool('').description('...').handler(...);
agent.tool(tool); // throws during agent's lazy build

// after
const tool = new Tool('search_docs').description('...').handler(...);
Defensive patterns

Strategy: validation

Validate before calling

function buildTool(name: string) {
  if (typeof name !== 'string' || name.trim().length === 0) {
    throw new Error('Tool name must be a non-empty string');
  }
  return new Tool(name);
}

Type guard

function isValidToolName(name: unknown): name is string {
  return typeof name === 'string' && name.trim().length > 0;
}

Prevention

When it happens

Trigger: Constructing new Tool('') (or new Tool(someVariable) where the variable resolves to '') and then either calling .build() directly or — per package convention — passing the builder to agent.tool(...)/agent.tools([...]) which builds internally.

Common situations: Dynamic tool construction from a config file or loop where a name field is missing or whitespace; refactoring and accidentally clearing a name; tests that instantiate Tool with a placeholder empty name.

Related errors


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