can1357/oh-my-pi · error · Error
Failed to move artifacts and rollback: ${rollbackErr instanc
Error message
Failed to move artifacts and rollback: ${rollbackErr instanceof Error ? rollbackErr.message : String(rollbackErr)} What it means
During a session directory move, artifacts (session artifacts directory) are relocated first. If the move then fails and a rollback of the artifacts directory via fs.rename back to its original location also fails, this combined error is thrown reporting the rollback failure. It means the artifacts directory is now in the NEW location and could not be restored, leaving the session split across old and new locations.
Source
Thrown at packages/coding-agent/src/session/session-manager.ts:1599
}
if (artifactPathChanged) {
try {
const artifactStat = await fs.promises.stat(oldArtifactsDir);
if (artifactStat.isDirectory()) {
await fs.promises.rename(oldArtifactsDir, newArtifactsDir);
artifactsMoved = true;
}
} catch (err) {
if (!isEnoent(err)) throw err;
}
}
} catch (err) {
if (artifactsMoved && oldArtifactsDir && newArtifactsDir) {
try {
await fs.promises.rename(newArtifactsDir, oldArtifactsDir);
} catch (rollbackErr) {
throw new Error(
`Failed to move artifacts and rollback: ${rollbackErr instanceof Error ? rollbackErr.message : String(rollbackErr)}`,
);
}
}
if (sessionMoved) {
try {
await fs.promises.rename(newSessionFile, oldSessionFile);
} catch (rollbackErr) {
throw new Error(
`Failed to move session file and rollback: ${rollbackErr instanceof Error ? rollbackErr.message : String(rollbackErr)}`,
);
}
}
throw err;
}
View on GitHub (pinned to 9690622007)
Solutions
- Manually rename the artifacts directory from the new location back to oldArtifactsDir using the inner error message for the cause.
- Remove whatever now occupies oldArtifactsDir (if stale) and retry the rollback.
- Copy-then-delete instead of rename if the locations are on different filesystems (EXDEV).
- Re-run the move operation to a consistent state, ensuring no concurrent process touches the session directories.
Example fix
// before: blind rename back fails on EXDEV
await fs.promises.rename(newArtifactsDir, oldArtifactsDir);
// after
try {
await fs.promises.rename(newArtifactsDir, oldArtifactsDir);
} catch {
await cp(newArtifactsDir, oldArtifactsDir, { recursive: true });
await fs.promises.rm(newArtifactsDir, { recursive: true });
} Defensive patterns
Strategy: try-catch
Validate before calling
if (existsSync(oldArtifactsDir)) {
throw new Error("Old artifacts dir already exists; move aborted beforehand");
} Type guard
null
Try / catch
try {
await mgr.moveSession(newCwd);
} catch (err) {
if (err.message.includes("Failed to move artifacts and rollback")) {
// artifacts are at the NEW location; relocate manually per err.message
} else throw err;
} Prevention
- Move sessions within the same filesystem so rename rollback works.
- Ensure no other process touches old/new artifact directories during a move.
- Check write permissions on both source and destination parents before moving.
When it happens
Trigger: Move-session operation throws after artifactsMoved is true, and the compensating rename(newArtifactsDir, oldArtifactsDir) fails — e.g. oldArtifactsDir was recreated in the meantime, destination is on another filesystem, or permissions deny the rename.
Common situations: Another process recreated the old directory during the move; cross-device rename (EXDEV); read-only parent directory; antivirus/file lock on Windows holding the directory.
Related errors
- No artifacts directory found: {artifacts_dir}
- could not relocate the session back to ${snapshot.sessionDir
- Failed to move session file and rollback: ${rollbackErr inst
- Cleanse session could not be persisted
- Session file not found: ${resolved}
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/d1d237bce431e3a1.
Report an issue: GitHub.