can1357/oh-my-pi · error · ToolError

Unknown URI-like write target '${trimmed}'. Did you mean 'xd

Error message

Unknown URI-like write target '${trimmed}'. Did you mean 'xd://${missingDelimiter[1]}'? Prefix the path with './' to write it as a filesystem path.

What it means

The write tool validates that its target path is either an absolute filesystem path or a routable URL. If the target looks like a URI but the scheme is missing the '//' after a colon (e.g. 'xd:foo' instead of 'xd://foo'), the tool refuses to guess and throws, telling you the exact corrected form. This exists to prevent silently creating a literal file named like a URI.

Source

Thrown at packages/coding-agent/src/tools/write.ts:120

	resolveXdevTool,
	type XdevDispatch,
	xdevActivitySummary,
	xdevListing,
} from "./xdev";

const LOOSE_HASHLINE_HEADER_RE = /^\s*\[[^#\r\n]+#[^ \t\r\n]*\]\s*$/;
const EXECUTABLE_NOTICE = "[Notice: Made executable via chmod +x]";
const URI_LIKE_WRITE_PATH_RE = /^([a-z][a-z0-9+.-]*):\/{1,2}(.*)$/i;
const XD_MISSING_DELIMITER_RE = /^xd\/+(.*)$/i;
const XD_SCHEME_NEAR_MISSES: Record<string, true> = { dx: true, xdd: true, xdt: true };

function assertWriteTargetAddressable(target: string, router: InternalUrlRouter): void {
	const trimmed = target.trim();
	if (path.win32.isAbsolute(trimmed) || router.canHandle(trimmed)) return;

	const missingDelimiter = trimmed.match(XD_MISSING_DELIMITER_RE);
	if (missingDelimiter) {
		throw new ToolError(
			`Unknown URI-like write target '${trimmed}'. Did you mean 'xd://${missingDelimiter[1]}'? Prefix the path with './' to write it as a filesystem path.`,
		);
	}

	const uriLike = trimmed.match(URI_LIKE_WRITE_PATH_RE);
	if (!uriLike) return;

	const scheme = uriLike[1]!.toLowerCase();
	// conflict:// has no router handler but is spliced downstream by
	// parseConflictUri (which emits its own precise id/scope errors); let it pass.
	if (scheme === "conflict") return;
	const canonicalScheme = router.getHandler(scheme) ? scheme : XD_SCHEME_NEAR_MISSES[scheme] ? "xd" : undefined;
	const suggestion = canonicalScheme
		? ` Did you mean '${canonicalScheme}://${uriLike[2]}'?`
		: " Tool devices use 'xd://<tool>'.";
	throw new ToolError(
		`Unknown URI-like write target '${trimmed}'.${suggestion} Prefix the path with './' to write it as a filesystem path.`,
	);

View on GitHub (pinned to 9690622007)

Solutions

  1. Add the missing '//' after the scheme: write 'xd://<tool>' instead of 'xd:<tool>'
  2. If you actually want a literal filesystem file, prefix the path with './' so it is treated as a relative path

Example fix

// before
write({ path: "xd:mem-1", content: "..." })
// after
write({ path: "xd://mem-1", content: "..." })
Defensive patterns

Strategy: validation

Validate before calling

const XD_MISSING_DELIMITER_RE = /^([a-z][a-z0-9+.-]*):(?![\/\/])(.+)/i;
function isWriteTargetAddressable(target: string, router: { canHandle(t: string): boolean }): boolean {
  const t = target.trim();
  if (path.win32.isAbsolute(t) || router.canHandle(t)) return true;
  return !XD_MISSING_DELIMITER_RE.test(t);
}
if (!isWriteTargetAddressable(p, router)) p = p.replace(/^([a-z][a-z0-9+.-]*):/i, "$1://");

Type guard

function isRoutableTarget(t: string, router: Router): boolean {
  return router.canHandle(t.trim()) || path.win32.isAbsolute(t.trim());
}

Try / catch

try {
  await write({ path: target, content });
} catch (e) {
  if (e instanceof ToolError && e.message.includes("Unknown URI-like write target")) {
    target = target.replace(/^([a-z][a-z0-9+.-]*):(?!\/\/)/i, "$1://");
    return write({ path: target, content });
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling write({ path: "xd:conflict-1" }) or any target matching a scheme-without-delimiter pattern like 'scheme:rest' that is not win32-absolute and not router-handled.

Common situations: Models or scripts omitting the '//' in custom scheme URLs (xd:, conflict:) when writing; pasting URIs from docs that dropped slashes.

Related errors


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