can1357/oh-my-pi · error · ToolError
This `write` tool is limited to the xd:// device transport:
Error message
This `write` tool is limited to the xd:// device transport: call it with path `xd://<tool>` and the device's JSON arguments in `content` (`read xd://` lists mounted devices). Active plan mode additionally permits its local artifact sandbox.
What it means
When the session is configured with deviceOnlyWrite, the write tool is restricted to the xd:// device transport (and, while plan mode is active, the local:// artifact sandbox). Any other path is rejected up front with this ToolError explaining the transport restriction and how to list mounted devices via `read xd://`.
Source
Thrown at packages/coding-agent/src/tools/write.ts:1132
// filesystem target. Without this, a model that pastes a `read`
// header as the `path` arg would slip past `isInternalUrlPath`
// (which fails on a leading `[`) and the bridge router would send a
// `[local://scratch.md#ABCD]` write to the editor instead of the
// session-local sandbox.
// Peel a read-tool selector (`:raw`, `:1-20`, …) so the write target matches
// what `read` resolves for the same URL; line-range/malformed selectors throw.
const path = peelWriteUrlSelector(unwrapHashlineHeaderPath(rawPath));
// A device-only session grants `write` purely as the xd:// transport (see
// createTools): device dispatches proceed, every other target is rejected
// before any handler, guard, conflict resolver, or bridge sees it. Active
// plan mode additionally permits its local artifact sandbox, but does not
// relax the restriction for working-tree or non-xd internal URLs.
if (
this.session.deviceOnlyWrite === true &&
!parseXdUrl(path) &&
!(this.session.getPlanModeState?.()?.enabled === true && targetsLocalSandbox(this.session, path))
) {
throw new ToolError(
"This `write` tool is limited to the xd:// device transport: call it with path `xd://<tool>` and the device's JSON arguments in `content` (`read xd://` lists mounted devices). Active plan mode additionally permits local:// sandbox drafts. Filesystem writes are not available elsewhere.",
);
}
return untilAborted(signal, async () => {
// Strip hashline display prefixes ([PATH#HASH] + LINE:) if the model copied them from read output
const { text: cleanContent, stripped } = stripWriteContent(this.session, content);
const internalRouter = InternalUrlRouter.instance();
assertWriteTargetAddressable(path, internalRouter);
if (internalRouter.canHandle(path)) {
const parsed = parseInternalUrl(path);
const scheme = parsed.protocol.replace(/:$/, "").toLowerCase();
const handler = internalRouter.getHandler(scheme);
if (handler?.write) {
// Handler-owned writes mutate user data outside the local
// sandbox. xd:// dispatches retain each wrapped tool's tier.
if (scheme !== "xd") {
enforcePlanModeWrite(this.session, path, { op: "update" });
emitWriteProgress(onUpdate, cleanContent, path);View on GitHub (pinned to 9690622007)
Solutions
- Rewrite the call to target `xd://<tool>` with the device's JSON arguments in content.
- Run `read xd://` to list mounted devices and their accepted arguments.
- If a local draft is appropriate, enable/use plan mode and write inside the local:// sandbox.
- If filesystem writes are genuinely needed, restart the session without deviceOnlyWrite.
Example fix
// before
await write("src/config.ts", "...")
// after
await write("xd://editor", "{ file: 'src/config.ts', content: '...' }") Defensive patterns
Strategy: validation
Validate before calling
const isXd = path.startsWith("xd://");
const isPlanSandbox = planModeEnabled && path.startsWith("local://");
if (deviceOnlyWrite && !isXd && !isPlanSandbox) {
throw new Error("Write must target xd:// (or local:// sandbox in plan mode)");
} Try / catch
try {
await write(path, content);
} catch (err) {
if (String(err.message).includes("limited to the xd:// device transport")) {
// re-dispatch as xd://<tool> with JSON content
}
throw err;
} Prevention
- In device-only sessions, route all writes through xd:// targets.
- Call `read xd://` first to learn mounted devices and their argument schemas.
- Use the local:// sandbox for drafts only while plan mode is active.
When it happens
Trigger: Calling write with a normal filesystem path (or non-xd internal URL) while session.deviceOnlyWrite === true and plan mode is not active (or the path is not inside the local sandbox).
Common situations: Agent working in a device-only session attempting to write workspace files; plan-mode drafts pointing outside the sanctioned sandbox; sessions launched with a restricted/device flag where the model still tries regular file edits.
Related errors
- {}: {error}
- inter-device move failed: {} to {}; unable to remove target:
- Permission denied
- cannot stat {file}: {error}
- failed to read filter definition {}: {e}
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/e5b97739e5d8e60a.
Report an issue: GitHub.