can1357/oh-my-pi · error
Artifact ${id} resolved to a directory, not a file
Error message
Artifact ${id} resolved to a directory, not a file What it means
After resolving an artifact id to a path, resolveArtifactFile stats the file and rejects directories. Artifact ids are expected to map to individual files; a directory match means the id resolution matched something the protocol cannot serve as content.
Source
Thrown at packages/coding-agent/src/internal-urls/artifact-protocol.ts:93
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;
async resolve(url: InternalUrl, context?: ResolveContext): Promise<InternalResource> {
const artifact = await resolveArtifactFile(url, context);
// Path-only callers (search/grep, bash URL expansion) never touch the
// artifact bytes. Return the resource shape so those flows keep working
// on artifacts of any size — only content materialization is gated.
if (context?.pathOnly) {
return {
url: url.href,
content: "",View on GitHub (pinned to 9690622007)
Solutions
- Point the artifact:// URL at a file id, not the directory
- Inspect the artifacts directory and remove or rename the directory that collides with an artifact id
- If a tool produced the directory, re-run the tool so it emits a file artifact
Example fix
// before
await resolve('artifact://bundle') // 'bundle' is a directory
// after
await resolve('artifact://bundle/index.html') // reference a file artifact Defensive patterns
Strategy: validation
Validate before calling
import { stat } from 'node:fs/promises'
const st = await stat(path)
if (st.isDirectory()) throw new Error(`${path} is a directory; pick a file artifact`) Try / catch
try {
return await resolve(`artifact://${id}`)
} catch (err) {
if (String(err).includes('resolved to a directory')) {
logger.warn('artifact id maps to a directory, skipping', { id })
return null
}
throw err
} Prevention
- Have tools emit files, not directories, as artifacts
- Avoid naming directories after artifact-id patterns under the artifacts dir
- Verify the resolved path is a file when scanning artifacts manually
When it happens
Trigger: An artifact id resolves to a directory path inside the artifacts directory — typically when the on-disk naming scheme contains a directory whose name collides with the id pattern, or a tool wrote a directory where a file was expected.
Common situations: Custom tooling wrote nested output (e.g. extracted archives) under the artifacts dir; an id was reused for a directory output; filesystem layout changed between tool versions.
Related errors
- target {0}: Not a directory
- unknown filetype: {ft_debug}
- Is a directory
- Too many levels of symbolic links
- {}: {error}
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/4e39ca5f45b764bc.
Report an issue: GitHub.