{"record":{"id":"b4834a8f9a028a24","repo":"can1357/oh-my-pi","slug":"vibe-tool-names-must-be-unique","errorCode":null,"errorMessage":"Vibe tool names must be unique.","messagePattern":"Vibe tool names must be unique\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/session/session-tools.ts","lineNumber":578,"sourceCode":"\n\t#wrapRuntimeTool(tool: AgentTool): AgentTool {\n\t\tconst wrapped = wrapToolWithMetaNotice(tool);\n\t\tconst extensionRunner = this.#host.extensionRunner();\n\t\treturn extensionRunner ? new ExtensionToolWrapper(wrapped, extensionRunner) : wrapped;\n\t}\n\n\t/** Installs and activates the ephemeral vibe tool set. */\n\tactivateVibeTools(baseToolNames: string[]): Promise<void> {\n\t\treturn this.runToolRegistryMutation(async () => {\n\t\t\tconst createVibeTools = this.#createVibeTools;\n\t\t\tif (!createVibeTools) {\n\t\t\t\tthrow new Error(\"Vibe tools are unavailable in this session.\");\n\t\t\t}\n\n\t\t\tconst tools = createVibeTools();\n\t\t\tconst vibeToolNames = tools.map(tool => tool.name);\n\t\t\tif (new Set(vibeToolNames).size !== vibeToolNames.length) {\n\t\t\t\tthrow new Error(\"Vibe tool names must be unique.\");\n\t\t\t}\n\n\t\t\tfor (const tool of tools) {\n\t\t\t\tif (this.#toolRegistry.has(tool.name)) continue;\n\t\t\t\tthis.#toolRegistry.set(tool.name, this.#wrapRuntimeTool(tool));\n\t\t\t\tthis.#builtInToolNames.add(tool.name);\n\t\t\t\tthis.#installedVibeToolNames.add(tool.name);\n\t\t\t}\n\n\t\t\tawait this.#applyActiveToolsByName([...new Set([...baseToolNames, ...vibeToolNames])]);\n\t\t});\n\t}\n\n\t/** Uninstalls vibe tools and activates the replacement set. */\n\tdeactivateVibeTools(nextToolNames: string[]): Promise<void> {\n\t\treturn this.runToolRegistryMutation(async () => {\n\t\t\tthis.#uninstallVibeTools();\n\t\t\tawait this.#applyActiveToolsByName(nextToolNames);","sourceCodeStart":560,"sourceCodeEnd":596,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/session/session-tools.ts#L560-L596","documentation":"activateVibeTools builds the vibe toolset via the injected factory and validates that the produced tool names are unique. If the factory returns two or more tools sharing a name, the registry would silently overwrite one, so the method throws this Error to surface the factory bug. It is a defensive invariant check, not something caller input causes directly.","triggerScenarios":"The createVibeTools factory returns a tool array with duplicate names — e.g. a custom factory registering the same tool twice, a misconfigured toolset composing overlapping sub-toolsets, or a bug in the built-in vibe tool list after customization.","commonSituations":"Users overriding or wrapping the vibe tool factory and accidentally including a tool already in the set; combining two tool packs that both expose e.g. 'read'; case/whitespace differences hiding intended duplicates.","solutions":["Inspect the tools returned by the createVibeTools factory and deduplicate by name before returning them.","If merging toolsets, filter out names already present instead of concatenating.","Fix name collisions by renaming one of the colliding tools in the factory.","Log vibeToolNames at factory time to identify exactly which name is duplicated."],"exampleFix":"// before (factory)\nconst tools = [...coreVibeTools, ...extraTools];\n// after\nconst seen = new Set();\nconst tools = [...coreVibeTools, ...extraTools].filter(t =>\n  seen.has(t.name) ? false : (seen.add(t.name), true)\n);","handlingStrategy":"validation","validationCode":"const names = tools.map(t => t.name);\nconst dupes = names.filter((n, i) => names.indexOf(n) !== i);\nif (dupes.length) throw new Error(`Vibe factory produced duplicate tool names: ${[...new Set(dupes)].join(\", \")}`);","typeGuard":null,"tryCatchPattern":"try {\n  await sessionTools.activateVibeTools(baseToolNames);\n} catch (err) {\n  if (err.message.includes(\"must be unique\")) {\n    logger.error(\"Vibe tool factory returned duplicate names — fix the factory\", { err });\n  } else throw err;\n}","preventionTips":["Deduplicate merged toolsets by name inside the factory before returning.","Rename colliding tools when composing multiple tool packs.","Test any custom createVibeTools factory for name uniqueness.","Avoid near-duplicate names differing only by case or whitespace."],"tags":["session","tools","invariant","duplicates"],"backgroundTag":"duplicate-tool-name","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}