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

  1. Deduplicate the tool list before sending it: filter by name so each name appears once.
  2. If you need two variants of a tool, give them distinct names (e.g. 'search_files' vs 'search_files_deep').
  3. 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

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


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/bf3157a291bd13ba. Report an issue: GitHub.