paperclipai/paperclip · error · Error
Unexpected attempt path ${join(source, entry.name)}
Error message
Unexpected attempt path ${join(source, entry.name)} What it means
copyAttempt enumerates the source attempt directory and only accepts entries that are real files (not symlinks) whose names are in the ATTEMPT_FILES allowlist. Any subdirectory, symlink, or unexpected file causes an abort so that only known attempt artifacts are copied into the campaign.
Source
Thrown at packages/paperclip-runner/scripts/runner-protocol-eval-campaign.mjs:243
Object.entries(entries)
.map(([key, value]) => `${key}=${value}\n`)
.join(""),
);
}
async function copyAttempt(source, destination) {
const metadata = await lstat(source);
if (!metadata.isDirectory() || metadata.isSymbolicLink()) {
throw new Error(`Attempt source is not a real directory: ${source}`);
}
await mkdir(destination, { recursive: false, mode: 0o700 });
for (const entry of await readdir(source, { withFileTypes: true })) {
if (
!entry.isFile() ||
entry.isSymbolicLink() ||
!ATTEMPT_FILES.has(entry.name)
) {
throw new Error(`Unexpected attempt path ${join(source, entry.name)}`);
}
await cp(join(source, entry.name), join(destination, entry.name), {
errorOnExist: true,
});
}
for (const required of [
"artifact.json",
"score.json",
"case.json",
"config.json",
]) {
await lstat(join(destination, required));
}
}
async function findFiles(root, name) {
const metadata = await lstat(root).catch(() => null);
if (!metadata) return [];View on GitHub (pinned to 01ad858492)
Solutions
- Remove the unexpected file/directory from the attempt folder (keep only files named in ATTEMPT_FILES).
- If the new file is a legitimate attempt artifact, add its exact name to the ATTEMPT_FILES set in the script.
- Clean OS-generated files (.DS_Store, Thumbs.db) before copying.
Example fix
// before const ATTEMPT_FILES = new Set(["result.json", "log.txt"]); // after const ATTEMPT_FILES = new Set(["result.json", "log.txt", "trace.json"]);
Defensive patterns
Strategy: validation
Validate before calling
const entries = await readdir(source, { withFileTypes: true });
const bad = entries.filter((e) => !e.isFile() || e.isSymbolicLink() || !ATTEMPT_FILES.has(e.name));
if (bad.length > 0) {
console.error("Unexpected entries:", bad.map((e) => e.name).join(", "));
} Type guard
function isAllowedAttemptEntry(e) {
return e.isFile() && !e.isSymbolicLink() && ATTEMPT_FILES.has(e.name);
} Try / catch
try {
await copyAttempt(source, dest);
} catch (err) {
if (err.message.startsWith("Unexpected attempt path")) {
console.error(err.message, "— remove the file or extend ATTEMPT_FILES");
process.exit(1);
}
throw err;
} Prevention
- Keep the attempt directory free of editor/OS artifacts (.DS_Store, swap files).
- When adding a new artifact produced by runs, update ATTEMPT_FILES in the same PR.
When it happens
Trigger: The attempt directory contains a file not listed in ATTEMPT_FILES, a subdirectory, or a symlinked entry; leftover logs, editor swap files (e.g. .DS_Store, vim swp), or partial-download files inside the attempt folder.
Common situations: A crashed run wrote extra output files into the attempt directory; OS artifact files (.DS_Store) created by browsing; someone added a new artifact file without updating ATTEMPT_FILES; an agent wrote debug output into the attempt folder.
Related errors
- ${label} is not a regular file at ${canonical}.
- workspace_durable_seed_invalid
- codex auth cache: account_id is not a valid account handle
- Pinned OpenCode source executable is not a regular file
- Unexpected trusted viewer asset
AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10).
Data as JSON: /api/errors/9b90d451dbc8ca2d.
Report an issue: GitHub.