can1357/oh-my-pi · error

No artifacts directory found

Error message

No artifacts directory found

What it means

resolveArtifactFile (packages/coding-agent/src/internal-urls/artifact-protocol.ts:82) throws when at least one session is registered, but none of the candidate artifacts directories exists on disk (every fs.readdir hit ENOENT). The registry references directories that were never created or have been deleted.

Source

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

			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);
			break;
		}
		for (const f of files) {
			const m = f.match(/^(\d+)\./);
			if (m) availableIds.add(m[1]);
		}
	}

	if (!anyDirExists) {
		throw new Error("No artifacts directory found");
	}

	if (!foundPath) {
		const sorted = [...availableIds].sort((a, b) => Number(a) - Number(b));
		const availableStr = sorted.length > 0 ? sorted.join(", ") : "none";
		throw new Error(`Artifact ${id} not found. Available: ${availableStr}`);
	}

	const stat = await Bun.file(foundPath).stat();
	if (stat.isDirectory()) {
		throw new Error(`Artifact ${id} resolved to a directory, not a file`);
	}
	return { id, path: foundPath, size: stat.size };
}

export class ArtifactProtocolHandler implements ProtocolHandler {
	readonly scheme = "artifact";
	readonly immutable = true;

View on GitHub (pinned to 9690622007)

Solutions

  1. Produce at least one artifact in the session so its artifacts directory is created, then retry.
  2. Verify the expected artifacts directory exists (session file path minus .jsonl suffix) and recreate it if it was deleted.
  3. Prune stale sessions from the persisted roster/AgentRegistry so dead dirs aren't scanned.
  4. Correct any misconfigured session/artifacts path pointing at a location that was removed or mounted elsewhere.

Example fix

// before
const res = await resolveArtifactFile(new URL("artifact://0")); // dir never created
// after
import * as fs from "node:fs/promises";
await fs.mkdir(artifactsDir, { recursive: true }); // ensure session dir exists
const res = await resolveArtifactFile(new URL("artifact://0"));
Defensive patterns

Strategy: validation

Validate before calling

import * as fs from "node:fs/promises";
import { artifactsDirsFromRegistry } from "./registry-helpers";
const dirs = artifactsDirsFromRegistry();
const ok = await Promise.all(dirs.map(d => fs.access(d).then(() => true, () => false)));
if (!ok.some(Boolean)) {
  await fs.mkdir(dirs[0], { recursive: true }); // or report: no artifacts directory exists
}

Type guard

function dirExists(p: string): boolean {
  try { return require("node:fs").statSync(p).isDirectory(); } catch { return false; }
}

Try / catch

try {
  const res = await resolveArtifactFile(url, context);
} catch (err) {
  if (err instanceof Error && err.message === "No artifacts directory found") {
    // session has produced no artifacts dir; create it or inform user
  } else throw err;
}

Prevention

When it happens

Trigger: Resolving any artifact:// URL when all registered session artifacts dirs are missing: a fresh session that has not yet written its first artifact, a deleted/stale session directory still listed in the persisted roster, or an artifacts dir path configured to a removed location.

Common situations: Pointing artifact tools at a session before any artifact was produced; cleaning artifacts dirs manually while old sessions remain in the roster; moving/copying session data without the artifacts subdirectories; different machine/container where session paths don't exist.

Related errors


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