can1357/oh-my-pi · error
RPC host tool names must be unique
Error message
RPC host tool names must be unique
What it means
#applyRpcHostToolRefresh validates an incoming batch of RPC-provided tools before merging them into the registry. If two or more tools in the same batch share a name, the refresh cannot build an unambiguous registry and throws. The registry requires globally unique tool names because the model dispatches tools by name.
Source
Thrown at packages/coding-agent/src/session/session-tools.ts:1825
await this.#applyActiveToolsByName(nextActive);
if (this.#host.isDisposed()) restorePreviousMcpTools();
} catch (error) {
restorePreviousMcpTools();
throw error;
}
}
/** Replaces RPC host-owned tools and refreshes the active set before the next model call. */
refreshRpcHostTools(rpcTools: AgentTool[]): Promise<void> {
const snapshot = [...rpcTools];
return this.runToolRegistryMutation(() => this.#applyRpcHostToolRefresh(snapshot));
}
async #applyRpcHostToolRefresh(rpcTools: AgentTool[]): Promise<void> {
const nextToolNames = rpcTools.map(tool => tool.name);
const uniqueToolNames = new Set(nextToolNames);
if (uniqueToolNames.size !== nextToolNames.length) {
throw new Error("RPC host tool names must be unique");
}
for (const name of uniqueToolNames) {
if (this.#toolRegistry.has(name) && !this.#rpcHostToolNames.has(name)) {
throw new Error(`RPC host tool "${name}" conflicts with an existing tool`);
}
}
const previousRpcHostToolNames = new Set(this.#rpcHostToolNames);
const previousActiveToolNames = this.getEnabledToolNames();
const previousRpcHostTools = new Map(
[...previousRpcHostToolNames].flatMap(name => {
const tool = this.#toolRegistry.get(name);
return tool ? [[name, tool] as const] : [];
}),
);
for (const name of previousRpcHostToolNames) {
this.#toolRegistry.delete(name);View on GitHub (pinned to 9690622007)
Solutions
- Deduplicate the tool list before sending it: filter by name so each name appears once.
- If you need two variants of a tool, give them distinct names (e.g. 'search_files' vs 'search_files_deep').
- Fix the RPC host side to send a fresh, unique array rather than appending to a previous list.
Example fix
// before await session.setRpcTools([...tools, ...tools]); // after const unique = [...new Map(tools.map(t => [t.name, t])).values()]; await session.setRpcTools(unique);
Defensive patterns
Strategy: validation
Validate before calling
const names = tools.map(t => t.name);
if (new Set(names).size !== names.length) {
throw new Error('duplicate RPC tool names: ' + names.filter((n, i) => names.indexOf(n) !== i));
} Try / catch
try {
await session.setRpcTools(tools);
} catch (err) {
if (err.message === 'RPC host tool names must be unique') {
const deduped = [...new Map(tools.map(t => [t.name, t])).values()];
await session.setRpcTools(deduped);
} else throw err;
} Prevention
- Deduplicate tool arrays by name before every refresh call.
- Generate tool names from a single source of truth.
- Add an assertion in your RPC host that outgoing tool names are unique.
When it happens
Trigger: Calling the RPC host tool refresh (setRpcTools / equivalent) with an AgentTool[] where `rpcTools.map(t => t.name)` contains duplicates (session-tools.ts:1824-1827).
Common situations: See trigger scenarios.
Related errors
- Host tool at index ${index} must provide a non-empty name
- Host tool "${name}" must provide a non-empty description
- Host tool "${name}" must provide a JSON Schema object
- Unsupported language '{value}'. Supported: {}
- Unable to infer language from file extension: {}. Specify `l
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/bf3157a291bd13ba.
Report an issue: GitHub.