can1357/oh-my-pi · error
Vibe tool names must be unique.
Error message
Vibe tool names must be unique.
What it means
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.
Source
Thrown at packages/coding-agent/src/session/session-tools.ts:578
#wrapRuntimeTool(tool: AgentTool): AgentTool {
const wrapped = wrapToolWithMetaNotice(tool);
const extensionRunner = this.#host.extensionRunner();
return extensionRunner ? new ExtensionToolWrapper(wrapped, extensionRunner) : wrapped;
}
/** Installs and activates the ephemeral vibe tool set. */
activateVibeTools(baseToolNames: string[]): Promise<void> {
return this.runToolRegistryMutation(async () => {
const createVibeTools = this.#createVibeTools;
if (!createVibeTools) {
throw new Error("Vibe tools are unavailable in this session.");
}
const tools = createVibeTools();
const vibeToolNames = tools.map(tool => tool.name);
if (new Set(vibeToolNames).size !== vibeToolNames.length) {
throw new Error("Vibe tool names must be unique.");
}
for (const tool of tools) {
if (this.#toolRegistry.has(tool.name)) continue;
this.#toolRegistry.set(tool.name, this.#wrapRuntimeTool(tool));
this.#builtInToolNames.add(tool.name);
this.#installedVibeToolNames.add(tool.name);
}
await this.#applyActiveToolsByName([...new Set([...baseToolNames, ...vibeToolNames])]);
});
}
/** Uninstalls vibe tools and activates the replacement set. */
deactivateVibeTools(nextToolNames: string[]): Promise<void> {
return this.runToolRegistryMutation(async () => {
this.#uninstallVibeTools();
await this.#applyActiveToolsByName(nextToolNames);View on GitHub (pinned to 9690622007)
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.
Example fix
// before (factory) const tools = [...coreVibeTools, ...extraTools]; // after const seen = new Set(); const tools = [...coreVibeTools, ...extraTools].filter(t => seen.has(t.name) ? false : (seen.add(t.name), true) );
Defensive patterns
Strategy: validation
Validate before calling
const names = tools.map(t => t.name);
const dupes = names.filter((n, i) => names.indexOf(n) !== i);
if (dupes.length) throw new Error(`Vibe factory produced duplicate tool names: ${[...new Set(dupes)].join(", ")}`); Try / catch
try {
await sessionTools.activateVibeTools(baseToolNames);
} catch (err) {
if (err.message.includes("must be unique")) {
logger.error("Vibe tool factory returned duplicate names — fix the factory", { err });
} else throw err;
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Cannot open a session writer before a session file exists
- Vibe tools are unavailable in this session.
- cachedContent cannot be combined with request-level ${incomp
- `context.tools` must be an array when present
- Tool "${toolCall.name}" not found
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/b4834a8f9a028a24.
Report an issue: GitHub.