can1357/oh-my-pi · error

No session - artifacts unavailable

Error message

No session - artifacts unavailable

What it means

resolveArtifactFile (packages/coding-agent/src/internal-urls/artifact-protocol.ts:54) throws when artifactsDirsFromRegistry() yields zero session artifact directories — i.e. no session is registered in the AgentRegistry, so artifacts cannot exist anywhere. Artifacts are per-session; without an active session there is nothing to resolve against.

Source

Thrown at packages/coding-agent/src/internal-urls/artifact-protocol.ts:54

}

/** Resolve an `artifact://` URL to its backing file without reading artifact bytes. */
export async function resolveArtifactFile(url: InternalUrl, context?: ResolveContext): Promise<ResolvedArtifactFile> {
	const id = parseArtifactId(url);

	// Artifact ids are per-session counters; in multi-session hosts the same
	// id exists in several dirs. Pin resolution to the calling session's
	// artifacts dir first so `artifact://3` means *this* session's #3.
	const dirs = artifactsDirsFromRegistry();
	const pinnedDir = context?.localProtocolOptions?.getArtifactsDir?.() ?? null;
	if (pinnedDir) {
		const pinnedIndex = dirs.indexOf(pinnedDir);
		if (pinnedIndex >= 0) dirs.splice(pinnedIndex, 1);
		dirs.unshift(pinnedDir);
	}

	if (dirs.length === 0) {
		throw new Error("No session - artifacts unavailable");
	}

	let foundPath: string | undefined;
	let anyDirExists = false;
	const availableIds = new Set<string>();

	for (const dir of dirs) {
		let files: string[];
		try {
			files = await fs.readdir(dir);
			anyDirExists = true;
		} catch (err) {
			if (isEnoent(err)) continue;
			throw err;
		}
		const match = files.find(f => f.startsWith(`${id}.`));
		if (match) {
			foundPath = path.join(dir, match);

View on GitHub (pinned to 9690622007)

Solutions

  1. Start/open a session first so the registry has an artifacts directory, then resolve artifact:// URLs.
  2. Ensure the resolving code runs inside the session host process, not a separate process with an empty registry.
  3. If embedding, register the session with AgentRegistry so artifactsDirsFromRegistry() returns at least one dir.
  4. Guard callers: skip artifact:// resolution when no session is active and surface a user-facing message instead.

Example fix

// before
const res = await resolveArtifactFile(url); // throws if no session
// after
import { AgentRegistry } from "../registry/agent-registry";
if (AgentRegistry.global().list().length === 0) {
  return "Artifacts are unavailable outside an active session.";
}
const res = await resolveArtifactFile(url);
Defensive patterns

Strategy: try-catch

Validate before calling

import { AgentRegistry } from "../registry/agent-registry";
const hasSession = AgentRegistry.global().list().length > 0;
if (!hasSession) {
  return "artifact:// URLs require an active session.";
}

Type guard

function sessionAvailable(registry: { list(): unknown[] }): boolean {
  return registry.list().length > 0;
}

Try / catch

try {
  const res = await resolveArtifactFile(url, context);
} catch (err) {
  if (err instanceof Error && err.message === "No session - artifacts unavailable") {
    return "Artifacts are unavailable outside an active session.";
  }
  throw err;
}

Prevention

When it happens

Trigger: Resolving any artifact:// URL outside an active session: no sessions registered in AgentRegistry.global(), calling the protocol handler from a bare script/SDK context before a session starts, or after the registry was cleared on session teardown.

Common situations: Running artifact:// resolution in a standalone test or worker process that never opened a session; invoking the resolver after the CLI session exited; embedding the library without initializing the agent registry.

Related errors


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