can1357/oh-my-pi · error · Error
Failed to move session file and rollback: ${rollbackErr inst
Error message
Failed to move session file and rollback: ${rollbackErr instanceof Error ? rollbackErr.message : String(rollbackErr)} What it means
Sibling of error 2074: after artifacts rollback, if the session file itself had already been moved (sessionMoved true) and the compensating rename(newSessionFile, oldSessionFile) fails, this error is thrown reporting that the session file could not be restored. The original triggering error is then also thrown. The session file ends up at the new location while the caller believes the move was aborted.
Source
Thrown at packages/coding-agent/src/session/session-manager.ts:1609
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;
}
if (sessionFileExisted && sessionPathChanged) {
this.#header.previousSessionFiles = [
...new Set([...(this.#header.previousSessionFiles ?? []), path.resolve(oldSessionFile)]),
];
}
this.#sessionFile = newSessionFile;
this.#artifactManager = null;
this.#artifactManagerSessionFile = null;
// Path is repointed; hot-path appends may use `#sessionFile` again.View on GitHub (pinned to 9690622007)
Solutions
- Manually move newSessionFile back to oldSessionFile (inner error names the cause).
- Close processes locking the file (editors, sync clients) and retry the rollback.
- If the old location is unrecoverable, accept the new location and update breadcrumbs/state accordingly.
- Use copy+delete as fallback when rename fails with EXDEV.
Example fix
// before
await fs.promises.rename(newSessionFile, oldSessionFile); // fails if locked
// after
closeHoldingProcesses();
try {
await fs.promises.rename(newSessionFile, oldSessionFile);
} catch (e) {
if (e.code === "EXDEV") {
await copyFile(newSessionFile, oldSessionFile);
await unlink(newSessionFile);
} else throw e;
} Defensive patterns
Strategy: try-catch
Validate before calling
if (existsSync(oldSessionFile)) {
throw new Error("Old session file still present; cannot roll back onto it");
} Type guard
null
Try / catch
try {
await mgr.moveSession(newCwd);
} catch (err) {
if (err.message.includes("Failed to move session file and rollback")) {
// session file is at the NEW location; restore manually per err.message
} else throw err;
} Prevention
- Close editors/sync clients that hold the session file open during moves.
- Keep moves on one filesystem (avoid EXDEV rollback failures).
- Verify the destination path is free and writable before initiating a session move.
When it happens
Trigger: Move-session operation fails after the session file rename succeeded, and rollback rename of the session file fails — destination occupied, cross-device move, permissions, or file locked by another process.
Common situations: Editor/indexer holding the session file open on Windows; old path recreated concurrently; EXDEV across mount points; read-only directory.
Related errors
- could not relocate the session back to ${snapshot.sessionDir
- Failed to move artifacts and rollback: ${rollbackErr instanc
- Cleanse session could not be persisted
- Session file not found: ${resolved}
- No artifacts directory found: {artifacts_dir}
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/cbe552036d07e63b.
Report an issue: GitHub.