{"record":{"id":"d1d237bce431e3a1","repo":"can1357/oh-my-pi","slug":"failed-to-move-artifacts-and-rollback-rollbacke","errorCode":null,"errorMessage":"Failed to move artifacts and rollback: ${rollbackErr instanceof Error ? rollbackErr.message : String(rollbackErr)}","messagePattern":"Failed to move artifacts and rollback: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/session/session-manager.ts","lineNumber":1599,"sourceCode":"\t\t\t\t\t}\n\n\t\t\t\t\tif (artifactPathChanged) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst artifactStat = await fs.promises.stat(oldArtifactsDir);\n\t\t\t\t\t\t\tif (artifactStat.isDirectory()) {\n\t\t\t\t\t\t\t\tawait fs.promises.rename(oldArtifactsDir, newArtifactsDir);\n\t\t\t\t\t\t\t\tartifactsMoved = true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch (err) {\n\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","sourceCodeStart":1581,"sourceCodeEnd":1617,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/session/session-manager.ts#L1581-L1617","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: blind rename back fails on EXDEV\nawait fs.promises.rename(newArtifactsDir, oldArtifactsDir);\n// after\ntry {\n  await fs.promises.rename(newArtifactsDir, oldArtifactsDir);\n} catch {\n  await cp(newArtifactsDir, oldArtifactsDir, { recursive: true });\n  await fs.promises.rm(newArtifactsDir, { recursive: true });\n}","handlingStrategy":"try-catch","validationCode":"if (existsSync(oldArtifactsDir)) {\n  throw new Error(\"Old artifacts dir already exists; move aborted beforehand\");\n}","typeGuard":"null","tryCatchPattern":"try {\n  await mgr.moveSession(newCwd);\n} catch (err) {\n  if (err.message.includes(\"Failed to move artifacts and rollback\")) {\n    // artifacts are at the NEW location; relocate manually per err.message\n  } else throw err;\n}","preventionTips":["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."],"tags":["session","filesystem","artifacts","rollback"],"backgroundTag":"filesystem-rollback-failed","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}