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
- Use one of the mounted device names listed in the error message.
- Fix the spelling of the device name (check for case/typo differences).
- Mount the needed device in the session before dispatching to it.
- 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
- Cache the mounted device list at session start and validate names against it.
- Fix typos by exact-match lookup rather than guessing.
- Mount required devices before dispatching.
- Prefer top-level tool calls when the alias may not be available.
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
- Cannot write to xd:// itself — pick a device:\n${xdevListing
- ${XD_URL_PREFIX}${device.name} expects a JSON args object as
- ${XD_URL_PREFIX}${device.name} content must be a JSON object
- Invalid args for ${XD_URL_PREFIX}${device.name}: ${message}\
- ${error.message} (rethrown as ToolError from StructuredSubag
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/149c5227ecfad159.
Report an issue: GitHub.