can1357/oh-my-pi · error

xd:// is not mounted in this session.

Error message

xd:// is not mounted in this session.

What it means

XdProtocolHandler.resolve routes xd:// virtual tool-device URLs to a per-session 'xd' mount. The handler only has access to the device registry through ResolveContext.xd; when the session was created without an xd mount, the protocol cannot serve content, so resolve throws immediately after URL parsing succeeds. It signals that the URL scheme is recognized but the backing device layer is absent from this session.

Source

Thrown at packages/coding-agent/src/internal-urls/xd-protocol.ts:35

}

/** Whether a streaming path prefix could still become an `xd://` URL. */
export function couldBecomeXdUrl(partialPath: string): boolean {
	if (partialPath.length <= XD_URL_PREFIX.length) {
		return XD_URL_PREFIX.startsWith(partialPath.toLowerCase());
	}
	return partialPath.toLowerCase().startsWith(XD_URL_PREFIX);
}

/** Routes session-bound virtual tool devices through `xd://` URLs. */
export class XdProtocolHandler implements ProtocolHandler {
	readonly scheme = "xd";
	readonly immutable = true;

	async resolve(url: InternalUrl, context?: ResolveContext): Promise<InternalResource> {
		const target = parseXdUrl(url.href);
		if (!target) throw new Error(`Invalid xd:// URL: ${url.href}. Use xd:// or xd://<tool>.`);
		if (!context?.xd) throw new Error("xd:// is not mounted in this session.");
		const content = await context.xd.read(target.name);
		return { url: url.href, content, contentType: "text/plain", size: Buffer.byteLength(content) };
	}

	async write(url: InternalUrl, content: string, context?: WriteContext): Promise<void> {
		const target = parseXdUrl(url.href);
		if (!target) throw new Error(`Invalid xd:// URL: ${url.href}. Use xd://<tool>.`);
		if (!context?.xd) throw new Error("xd:// is not mounted in this session.");
		await context.xd.write(target.name, content);
	}
}

View on GitHub (pinned to 9690622007)

Solutions

  1. Create/enable the session's xd mount so ResolveContext.xd is populated, then retry the resolve
  2. If the xd device is not needed, treat the URL as unresolvable in the caller and skip xd:// hrefs instead of resolving them
  3. Check that the context object passed to resolve is the session's real resolve context, not a stale or default-built one

Example fix

// before
await handler.resolve(url, { /* no xd mount */ });
// after
const ctx = session.getResolveContext(); // includes xd when the session mounts tool devices
if (!ctx.xd) throw new Error('This session has no xd mount; cannot resolve ' + url.href);
await handler.resolve(url, ctx);
Defensive patterns

Strategy: validation

Validate before calling

function canResolveXd(ctx: ResolveContext | undefined, href: string): boolean {
  const target = parseXdUrl(href);
  return target !== null && ctx?.xd !== undefined;
}
// call only if canResolveXd(ctx, url.href)

Type guard

function hasXdMount(ctx: ResolveContext | undefined): ctx is ResolveContext & { xd: NonNullable<ResolveContext['xd']> } {
  return ctx?.xd !== undefined;
}

Try / catch

try {
  const resource = await handler.resolve(url, ctx);
} catch (err) {
  if (err instanceof Error && err.message === 'xd:// is not mounted in this session.') {
    return null; // degrade gracefully: no xd device in this session
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling resolve() with an xd:// (or xd://<tool>) InternalUrl while the ResolveContext passed in has no `xd` property — e.g. a session built without the tool-device mount, or a bare/incorrectly-constructed context object.

Common situations: Embedding the coding-agent SDK and forgetting to configure the xd mount in session options; resolving an xd:// URL captured from a previous session that had the mount; test harnesses invoking the protocol handler with a hand-built context; resolving a URL read from a persisted transcript in a new session that lacks the device.

Related errors


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