can1357/oh-my-pi · error · ToolError

No such tool: ${XD_URL_PREFIX}${name}. Mounted devices: ${[.

Error message

No such tool: ${XD_URL_PREFIX}${name}. Mounted devices: ${[...state.mountedNames].join(", ")}. Active top-level tools are also dispatchable via ${XD_URL_PREFIX}<tool>.

What it means

resolveRequiredXdevTool looks up a device by name among the tools mounted in the xdev state. If no mounted device (and no active top-level tool alias) matches the requested name, it throws this ToolError listing all currently mounted device names and noting that top-level tools can also be dispatched via xd://<tool>.

Source

Thrown at packages/coding-agent/src/tools/xdev.ts:399

	return sections.join("\n\n");
}

function shouldInlineXdevTool(
	state: XdevState,
	tool: Tool,
	mode: XdevDocsMode,
	inlineGlobs: readonly Bun.Glob[],
): boolean {
	return (
		mode !== "catalog" &&
		(mode === "inline" || state.builtInNames.has(tool.name) || inlineGlobs.some(glob => glob.match(tool.name)))
	);
}

function resolveRequiredXdevTool(state: XdevState, name: string): Tool {
	const inst = resolveXdevTool(state, name);
	if (!inst) {
		throw new ToolError(
			`No such tool: ${XD_URL_PREFIX}${name}. Mounted devices: ${[...state.mountedNames].join(", ")}. Active top-level tools are also dispatchable via ${XD_URL_PREFIX}<tool>.`,
		);
	}
	return inst;
}

/** Execute an enabled canonical tool through `write xd://<tool>`. */
export async function dispatchXdevTool(
	state: XdevState,
	name: string,
	content: string,
	toolCallId: string,
	signal?: AbortSignal,
	onUpdate?: AgentToolUpdateCallback,
	context?: AgentToolContext,
): Promise<{ result: AgentToolResult<unknown>; xdev: XdevDispatch }> {
	let xdev: XdevDispatch = { tool: name, mode: "execute" };
	try {

View on GitHub (pinned to 9690622007)

Solutions

  1. Use one of the mounted device names listed in the error message.
  2. Fix the spelling of the device name (check for case/typo differences).
  3. Mount the needed device in the session before dispatching to it.
  4. Call the tool directly (top-level) if appropriate, or via `xd://<tool>` only for active top-level tools.

Example fix

// before
write({ path: "xd://browsers", content: "{...}" })
// after
write({ path: "xd://browser", content: "{...}" }) // name from mounted list
Defensive patterns

Strategy: validation

Validate before calling

if (!mountedDevices.includes(name)) throw new Error(`xd device not mounted: ${name}. Available: ${mountedDevices.join(", ")}`);

Type guard

function isMounted(name: string, state: { mountedNames: Iterable<string> }): boolean { return new Set(state.mountedNames).has(name); }

Try / catch

try { await dispatch(path, content); } catch (e) { if (String(e.message).startsWith("No such tool:")) { const mounted = e.message.match(/Mounted devices: ([^.]+)/)?.[1]?.split(", ") ?? []; /* pick correct or mount device */ } else throw e; }

Prevention

When it happens

Trigger: Calling Write/dispatch with `xd://<name>` where <name> is misspelled, not mounted in this session, or refers to a tool that exists but was excluded/unmounted.

Common situations: Typo in the device name; the session was started without mounting that device; a device was renamed across versions; assuming every top-level tool is available under xd:// when it was excluded.

Related errors


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