{"record":{"id":"30b730214841ccb4","repo":"n8n-io/n8n","slug":"deferred-tool-name-tool-name-is-reserved","errorCode":null,"errorMessage":"Deferred tool name \"${tool.name}\" is reserved","messagePattern":"Deferred tool name \"(.+?)\" is reserved","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/@n8n/agents/src/runtime/tools/deferred-tool-manager.ts","lineNumber":93,"sourceCode":"export interface DeferredToolManagerOptions {\n\ttopK?: number;\n}\n\nexport class DeferredToolManager {\n\tprivate readonly toolsByName = new Map<string, BuiltTool>();\n\n\tprivate readonly loadedToolNames = new Set<string>();\n\n\tprivate readonly topK: number;\n\n\tprivate readonly searchTool: BuiltTool;\n\n\tprivate readonly loadTool: BuiltTool;\n\n\tconstructor(tools: BuiltTool[], options: DeferredToolManagerOptions = {}) {\n\t\tfor (const tool of tools) {\n\t\t\tif (tool.name === SEARCH_TOOLS_TOOL_NAME || tool.name === LOAD_TOOL_TOOL_NAME) {\n\t\t\t\tthrow new Error(`Deferred tool name \"${tool.name}\" is reserved`);\n\t\t\t}\n\t\t\tif (this.toolsByName.has(tool.name)) {\n\t\t\t\tthrow new Error(`Duplicate deferred tool name \"${tool.name}\"`);\n\t\t\t}\n\t\t\tthis.toolsByName.set(tool.name, tool);\n\t\t}\n\n\t\tthis.topK = options.topK ?? DEFAULT_TOP_K;\n\t\tthis.searchTool = this.createSearchTool();\n\t\tthis.loadTool = this.createLoadTool();\n\t}\n\n\tget hasTools(): boolean {\n\t\treturn this.toolsByName.size > 0;\n\t}\n\n\tget totalToolCount(): number {\n\t\treturn this.toolsByName.size;","sourceCodeStart":75,"sourceCodeEnd":111,"githubUrl":"https://github.com/n8n-io/n8n/blob/5ac6606e81f67bb9534255570cd4e86fd8101eee/packages/@n8n/agents/src/runtime/tools/deferred-tool-manager.ts#L75-L111","documentation":"`DeferredToolManager` exposes two built-in controller tools — `search_tools` and `load_tool` — that let the agent discover and load tools on demand. To avoid name collisions, any tool passed to the constructor whose `name` matches these reserved names throws immediately. The manager cannot function if a deferred tool shadows its own controllers.","triggerScenarios":"Passing a tool with `name: 'search_tools'` or `name: 'load_tool'` to `new DeferredToolManager([...])`. This happens when a user-defined or integration tool happens to use one of these names.","commonSituations":"A custom tool or MCP-imported tool was named `search_tools` or `load_tool`. A tool catalog contains a tool with a colliding name. A code generation or naming convention accidentally produced a reserved name.","solutions":["Rename the conflicting tool to something other than `search_tools` or `load_tool`.","If the name comes from an external source (MCP server, tool catalog), map/rename it before passing to the constructor.","Filter or validate tool names against `[SEARCH_TOOLS_TOOL_NAME, LOAD_TOOL_TOOL_NAME]` before constructing the manager."],"exampleFix":"// before:\nconst mgr = new DeferredToolManager([\n  { name: 'search_tools', ... }, // collides with built-in\n]);\n\n// after:\nconst mgr = new DeferredToolManager([\n  { name: 'find_integrations', ... }, // renamed\n]);","handlingStrategy":"validation","validationCode":"import { SEARCH_TOOLS_TOOL_NAME, LOAD_TOOL_TOOL_NAME } from './deferred-tool-manager';\n\nconst RESERVED = new Set([SEARCH_TOOLS_TOOL_NAME, LOAD_TOOL_TOOL_NAME]);\n\nfunction sanitizeToolNames(tools: BuiltTool[]): BuiltTool[] {\n  return tools.filter((t) => {\n    if (RESERVED.has(t.name)) {\n      logger.warn(`Tool name \"${t.name}\" is reserved, skipping`);\n      return false;\n    }\n    return true;\n  });\n}\n\nconst mgr = new DeferredToolManager(sanitizeToolNames(allTools));","typeGuard":"function isNotReservedToolName(tool: BuiltTool): boolean {\n  return tool.name !== 'search_tools' && tool.name !== 'load_tool';\n}","tryCatchPattern":null,"preventionTips":["Filter tool names against the reserved set before constructing DeferredToolManager.","Namespace MCP-imported tool names to avoid collisions with built-in names.","Validate tool names at registration time."],"tags":["tools","deferred-tools","validation","naming","reserved"],"backgroundTag":null,"analyzedSha":"5ac6606e81f67bb9534255570cd4e86fd8101eee","analyzedAt":"2026-08-12T05:26:35.080Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}