EveryInc/compound-engineering-plugin · error · Error
Could not validate ${collectionPath} after taking it. The en
Error message
Could not validate ${collectionPath} after taking it. The entry is preserved at ${recoveryPath} (${reason}) What it means
removeManagedCollectionLink() moves the entry to a temp recovery directory and hands it to options.onTakenForTest for post-removal validation. If that callback throws, the original entry is kept at recoveryPath and the code re-raises with its location so nothing is lost. This is a safety net ensuring the 'taken' entry is never silently dropped when validation cannot complete.
Source
Thrown at src/dev/codex-dev.ts:316
const parentPath = path.dirname(collectionPath)
const recoveryDir = await fs.mkdtemp(
path.join(parentPath, `.${path.basename(collectionPath)}.recovery-`),
)
const recoveryPath = path.join(recoveryDir, "entry")
try {
await fs.rename(collectionPath, recoveryPath)
} catch (error) {
await fs.rmdir(recoveryDir).catch(() => undefined)
if ((error as NodeJS.ErrnoException).code === "ENOENT") return changed()
throw error
}
try {
await options.onTakenForTest?.(recoveryPath)
} catch (error) {
const reason = error instanceof Error ? error.message : String(error)
throw new Error(
`Could not validate ${collectionPath} after taking it. ` +
`The entry is preserved at ${recoveryPath} (${reason})`,
)
}
const stat = await fs.lstat(recoveryPath)
let actualTarget: string | undefined
if (stat.isSymbolicLink()) {
actualTarget = await fs.readlink(recoveryPath)
}
if (stat.isSymbolicLink() && actualTarget === expectedTarget) {
await fs.unlink(recoveryPath)
await fs.rmdir(recoveryDir)
return true
}
const restorationFailed = (error: unknown): never => {View on GitHub (pinned to c9c10f8c75)
Solutions
- Read the recoveryPath from the error message — the original entry is intact there
- Check free space and write permissions on the OS temp directory used for recoveryPath
- Manually move the entry back: `mv <recoveryPath> <collectionPath>` to restore the previous state
- Re-run the removal after fixing the underlying validation failure
Example fix
// before — recovery dir unwritable, callback fails // Error: Could not validate ... (EACCES: permission denied, scandir '/tmp/...') // after $ TMPDIR=/tmp # or fix perms on the configured temp dir $ mv "$recoveryPath" "$collectionPath" && retry the codex:dev command
Defensive patterns
Strategy: try-catch
Validate before calling
import { fs } from "...";
await fs.access(path.dirname(recoveryPath)); // recovery dir is readable
const stat = await fs.stat(recoveryPath); // taken entry actually exists Try / catch
try {
await removeLocalCollection(context);
} catch (e) {
const m = String(e).match(/preserved at (\S+)/);
if (m) console.error(`original entry kept at ${m[1]}; restore manually if needed`);
else throw e;
} Prevention
- Ensure the OS temp directory is writable and has free space
- Avoid running under sandboxes that deny access to $TMPDIR
- Keep onTakenForTest callbacks simple and side-effect free
When it happens
Trigger: The onTakenForTest callback supplied by replaceManagedCollectionLink / restoreLocalCollection / removeLocalCollection throws — any filesystem error while validating or restoring the taken entry (permission denied, ENOENT on the recovery path, disk full).
Common situations: Temp directory on a read-only or full volume so the recovery copy cannot be read back; sandbox/permissions blocking access to the mkdtemp recovery directory; a bug in the caller's validation callback throwing spuriously.
Related errors
- ${collectionPath} changed since it was inspected; refusing t
- No Codex skills were found under ${skillsRoot}
- ${context.collectionPath} is a broken symlink; refusing to o
- ${collectionPath} changed since it was inspected; refusing t
- ${context.collectionPath} exists and is not a symlink; refus
AI-assisted analysis of EveryInc/compound-engineering-plugin@c9c10f8c75 (2026-08-31).
Data as JSON: /api/errors/80bc2589562fb462.
Report an issue: GitHub.