can1357/oh-my-pi · error · ToolError
Cannot write to xd:// itself — pick a device:\n${xdevListing
Error message
Cannot write to xd:// itself — pick a device:\n${xdevListing(xdev)} What it means
WriteTool supports special internal URLs like xd:// in place of a normal file path. Writing to the bare `xd://` URL has no meaning — xd:// is a device namespace, so the tool requires a device name (`xd://<device>`). It throws this ToolError and prints a listing of the mounted xdev devices so the caller can pick one.
Source
Thrown at packages/coding-agent/src/tools/write.ts:1183
};
return;
}
if (name && isResolutionDeviceName(name)) {
const { result, xdev } = await dispatchResolutionDevice(this.session, name, deviceContent);
xdResult = {
content: result.content,
details: { xdev },
isError: result.isError,
useless: result.useless,
};
return;
}
const xdev = this.session.xdev;
if (!xdev) {
throw new ToolError("xd:// is not mounted in this session.");
}
if (!name) {
throw new ToolError(`Cannot write to xd:// itself — pick a device:\n${xdevListing(xdev)}`);
}
const { result, xdev: dispatch } = await dispatchXdevTool(
xdev,
name,
deviceContent,
_toolCallId,
signal,
onUpdate as AgentToolUpdateCallback,
// The write tool's own gate just resolved approval at this
// device's tier (see #approval above) — mark it so a wrapped
// inner tool does not prompt a second time.
context ? { ...context, xdevApproved: true } : undefined,
);
xdResult = {
content: result.content,
details: { xdev: dispatch },
isError: result.isError,
useless: result.useless,View on GitHub (pinned to 9690622007)
Solutions
- Append the target device name: write to `xd://<device>` instead of `xd://`.
- Check the device list printed in the error message (from xdevListing) and use one of the listed names.
- Use the session's mounted xd:// devices or a regular filesystem path if no xdev device is intended.
- If no device is needed at all, write to a normal file path instead of an xd:// URL.
Example fix
// before
write({ path: "xd://", content: "..." })
// after
write({ path: "xd://browser", content: "..." }) Defensive patterns
Strategy: validation
Validate before calling
if (path === "xd://" || path === "xd:///") throw new Error("Pick a device: use xd://<device>, e.g. xd://browser"); Type guard
function isBareXdevRoot(path: string): boolean { return path.replace(/\/$/, "") === "xd://"; } Try / catch
try { await write({ path, content }); } catch (e) { if (String(e.message).startsWith("Cannot write to xd:// itself")) { const devices = e.message.split("\n").slice(1); /* retry with a listed device */ } else throw e; } Prevention
- Never target the bare xd:// root; always include a device name.
- Keep the device listing from the error and choose from it.
- For plain files, use normal filesystem paths instead of xd://.
- Validate URL scheme+authority before dispatching writes.
When it happens
Trigger: Calling the Write tool with path exactly `xd://` (no device name) while xdev is mounted in the session; typically when the model abbreviates an intended `xd://<device>` target.
Common situations: An LLM agent emits `xd://` as a shorthand target when composing a write, or truncates the device name from a previously successful xd:// call.
Related errors
- ${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}\
- No such tool: ${XD_URL_PREFIX}${name}. Mounted devices: ${[.
- ${error.message} (rethrown as ToolError from StructuredSubag
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/ee3d60c661612fb3.
Report an issue: GitHub.