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

  1. Rewrite the call to target `xd://<tool>` with the device's JSON arguments in content.
  2. Run `read xd://` to list mounted devices and their accepted arguments.
  3. If a local draft is appropriate, enable/use plan mode and write inside the local:// sandbox.
  4. 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

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


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