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

  1. Append the target device name: write to `xd://<device>` instead of `xd://`.
  2. Check the device list printed in the error message (from xdevListing) and use one of the listed names.
  3. Use the session's mounted xd:// devices or a regular filesystem path if no xdev device is intended.
  4. 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

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


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