can1357/oh-my-pi · error

No session - local:// unavailable

Error message

No session - local:// unavailable

What it means

LocalProtocolHandler.resolve needs a LocalProtocolOptions (artifacts dir + session id providers) sourced from the call context, a process-global override, or a registered main session in AgentRegistry. If all three are absent there is no session-scoped local root to resolve against, so the handler throws this error rather than guessing a location.

Source

Thrown at packages/coding-agent/src/internal-urls/local-protocol.ts:487

		const fromContext = context?.localProtocolOptions;
		if (fromContext) return fromContext;
		const override = LocalProtocolHandler.#override;
		if (override) return override;
		const main = AgentRegistry.global()
			.list()
			.find(ref => ref.kind === "main");
		const sessionManager = main?.session?.sessionManager;
		if (!sessionManager) return undefined;
		return {
			getArtifactsDir: () => sessionManager.getArtifactsDir(),
			getSessionId: () => sessionManager.getSessionId(),
		};
	}

	async resolve(url: InternalUrl, context?: ResolveContext): Promise<InternalResource> {
		const opts = LocalProtocolHandler.resolveOptions(context);
		if (!opts) {
			throw new Error("No session - local:// unavailable");
		}

		const resolved = await resolveLocalTarget(url, opts);
		if (resolved.kind === "listing") {
			return buildListing(url, resolved.root);
		}
		if (resolved.kind === "directory") {
			return buildDirectoryResource(url.href, resolved.path, [LOCAL_WRITE_NOTE]);
		}

		return buildFileResource(url, resolved);
	}

	async complete(_query?: string, context?: ResolveContext): Promise<UrlCompletion[]> {
		const opts = LocalProtocolHandler.resolveOptions(context);
		if (!opts) return [];
		const localRoot = path.resolve(resolveLocalRoot(opts));
		try {

View on GitHub (pinned to 9690622007)

Solutions

  1. Create/register an agent session (main kind) before resolving local:// URLs, or run the resolution inside an active session so the context carries localProtocolOptions.
  2. For SDK embedders, call LocalProtocolHandler.setOverride({ getArtifactsDir, getSessionId }) with your own mapping.
  3. Pass context: { localProtocolOptions } explicitly on the resolve/read call in multi-session hosts.

Example fix

// before
await router.resolve("local://notes.md"); // no session
// after
LocalProtocolHandler.setOverride({
  getArtifactsDir: () => artifactsDir,
  getSessionId: () => sessionId,
});
await router.resolve("local://notes.md");
Defensive patterns

Strategy: type-guard

Validate before calling

import { LocalProtocolHandler } from './local-protocol';
const opts = LocalProtocolHandler.resolveOptions(context);
if (!opts) throw new Error('No active session: cannot resolve local:// URLs');

Type guard

function hasLocalOptions(context) { return Boolean(context?.localProtocolOptions ?? LocalProtocolHandler.resolveOptions(context)); }

Try / catch

try { resource = await handler.resolve(url, ctx); } catch (e) { if (e.message === 'No session - local:// unavailable') { /* initialize/register a session or set an override before retrying */ } else throw e; }

Prevention

When it happens

Trigger: Calling router.resolve/read with a local:// URL before any agent session is created; SDK consumers that never wired localProtocolOptions (neither context.localProtocolOptions nor LocalProtocolHandler.setOverride) and have no AgentRegistry main session; tool invocations in worker processes where the registry was not populated.

Common situations: Standalone scripts embedding the SDK and resolving local:// URLs outside a session lifecycle; tests invoking the handler without registering a session; TUI/plugins running before session startup completes.

Related errors


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