{"record":{"id":"cbe552036d07e63b","repo":"can1357/oh-my-pi","slug":"failed-to-move-session-file-and-rollback-rollba","errorCode":null,"errorMessage":"Failed to move session file and rollback: ${rollbackErr instanceof Error ? rollbackErr.message : String(rollbackErr)}","messagePattern":"Failed to move session file and rollback: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/session/session-manager.ts","lineNumber":1609,"sourceCode":"\t\t\t\t\t\t\tif (!isEnoent(err)) throw err;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} catch (err) {\n\t\t\t\t\tif (artifactsMoved && oldArtifactsDir && newArtifactsDir) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tawait fs.promises.rename(newArtifactsDir, oldArtifactsDir);\n\t\t\t\t\t\t} catch (rollbackErr) {\n\t\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t\t`Failed to move artifacts and rollback: ${rollbackErr instanceof Error ? rollbackErr.message : String(rollbackErr)}`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (sessionMoved) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tawait fs.promises.rename(newSessionFile, oldSessionFile);\n\t\t\t\t\t\t} catch (rollbackErr) {\n\t\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t\t`Failed to move session file and rollback: ${rollbackErr instanceof Error ? rollbackErr.message : String(rollbackErr)}`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tthrow err;\n\t\t\t\t}\n\n\t\t\t\tif (sessionFileExisted && sessionPathChanged) {\n\t\t\t\t\tthis.#header.previousSessionFiles = [\n\t\t\t\t\t\t...new Set([...(this.#header.previousSessionFiles ?? []), path.resolve(oldSessionFile)]),\n\t\t\t\t\t];\n\t\t\t\t}\n\n\t\t\t\tthis.#sessionFile = newSessionFile;\n\t\t\t\tthis.#artifactManager = null;\n\t\t\t\tthis.#artifactManagerSessionFile = null;\n\t\t\t\t// Path is repointed; hot-path appends may use `#sessionFile` again.","sourceCodeStart":1591,"sourceCodeEnd":1627,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/session/session-manager.ts#L1591-L1627","documentation":"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.","triggerScenarios":"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.","commonSituations":"Editor/indexer holding the session file open on Windows; old path recreated concurrently; EXDEV across mount points; read-only directory.","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."],"exampleFix":"// before\nawait fs.promises.rename(newSessionFile, oldSessionFile); // fails if locked\n// after\ncloseHoldingProcesses();\ntry {\n  await fs.promises.rename(newSessionFile, oldSessionFile);\n} catch (e) {\n  if (e.code === \"EXDEV\") {\n    await copyFile(newSessionFile, oldSessionFile);\n    await unlink(newSessionFile);\n  } else throw e;\n}","handlingStrategy":"try-catch","validationCode":"if (existsSync(oldSessionFile)) {\n  throw new Error(\"Old session file still present; cannot roll back onto it\");\n}","typeGuard":"null","tryCatchPattern":"try {\n  await mgr.moveSession(newCwd);\n} catch (err) {\n  if (err.message.includes(\"Failed to move session file and rollback\")) {\n    // session file is at the NEW location; restore manually per err.message\n  } else throw err;\n}","preventionTips":["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."],"tags":["session","filesystem","rollback"],"backgroundTag":"filesystem-rollback-failed","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}