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
- Create/enable the session's xd mount so ResolveContext.xd is populated, then retry the resolve
- If the xd device is not needed, treat the URL as unresolvable in the caller and skip xd:// hrefs instead of resolving them
- 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
- Verify session options enable the xd mount before storing/resolving xd:// hrefs
- Route URL resolution through a dispatcher that checks the scheme and available mounts first
- When persisting transcripts, record which mounts the session had so future sessions can skip unavailable schemes
- In SDK embeddings, always build the context from the session factory rather than hand-assembling it
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
- Invalid xd:// URL: ${url.href}. Use xd://<tool>.
- Output ${scan.matchedId} is not valid JSON: ${message}
- artifact:// URL requires a numeric ID: artifact://0
- artifact:// ID must be numeric, got: ${id}
- No session - artifacts unavailable
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/161d0d727c625562.
Report an issue: GitHub.