{"record":{"id":"d7e3c193e54a4d88","repo":"can1357/oh-my-pi","slug":"archive-destination-exists-legacydestsession","errorCode":null,"errorMessage":"archive destination exists: ${legacyDestSession}","messagePattern":"archive destination exists: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/cli/gc-cli.ts","lineNumber":527,"sourceCode":"\t\tthrow error;\n\t}\n}\n\nasync function restoreGzipSessionFile(source: string, destination: string): Promise<void> {\n\tawait fs.mkdir(path.dirname(destination), { recursive: true });\n\tconst decompressed = gunzipSync(await Bun.file(source).bytes());\n\tawait Bun.write(destination, decompressed);\n\tawait fs.unlink(source);\n}\n\nasync function moveSessionWithArtifacts(candidate: ArchiveCandidate): Promise<void> {\n\tconst sourceSession = candidate.session.path;\n\tconst destSession = candidate.destinationPath;\n\tconst legacyDestSession = destSession.endsWith(\".gz\") ? destSession.slice(0, -\".gz\".length) : `${destSession}.gz`;\n\tconst sourceArtifacts = sessionArtifactsPath(sourceSession);\n\tconst destArtifacts = sessionArtifactsPath(destSession);\n\tif (await pathExists(destSession)) throw new Error(`archive destination exists: ${destSession}`);\n\tif (await pathExists(legacyDestSession)) throw new Error(`archive destination exists: ${legacyDestSession}`);\n\tif ((await pathExists(sourceArtifacts)) && (await pathExists(destArtifacts))) {\n\t\tthrow new Error(`archive artifacts destination exists: ${destArtifacts}`);\n\t}\n\n\tconst moved: Array<{ source: string; destination: string; compressed?: boolean }> = [];\n\ttry {\n\t\tawait gzipSessionFile(sourceSession, destSession);\n\t\tmoved.push({ source: sourceSession, destination: destSession, compressed: true });\n\t\tif (await pathExists(sourceArtifacts)) {\n\t\t\tawait movePath(sourceArtifacts, destArtifacts);\n\t\t\tmoved.push({ source: sourceArtifacts, destination: destArtifacts });\n\t\t}\n\t} catch (error) {\n\t\tfor (const move of moved.reverse()) {\n\t\t\ttry {\n\t\t\t\tif (move.compressed) {\n\t\t\t\t\tawait restoreGzipSessionFile(move.destination, move.source);\n\t\t\t\t} else {","sourceCodeStart":509,"sourceCodeEnd":545,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/cli/gc-cli.ts#L509-L545","documentation":"The legacy-destination counterpart of the archive collision check: when the computed destination is `X.gz`, the code also guards the uncompressed `X` (and vice versa) so a leftover archive from an older naming scheme still blocks the move instead of being overwritten.","triggerScenarios":"Archiving a session when the legacy path (destination with the .gz suffix stripped, or appended) already exists — typically left behind by a previous GC run that used the older naming convention or crashed midway.","commonSituations":"Upgraded omp versions changing archive naming; a previous run interrupted between gzip and cleanup; manual decompression of an old archive recreating the uncompressed file at the legacy path.","solutions":["Inspect the legacy path in the message; delete or move the stale file if it is redundant","Verify the existing archive is intact/needed before deleting (it may be the previous successful archive of the same session)","Re-run GC after clearing the collision"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"import * as fs from \"node:fs/promises\";\nconst legacy = dest.endsWith(\".gz\") ? dest.slice(0, -3) : `${dest}.gz`;\ntry { await fs.access(legacy); throw new Error(`legacy destination exists: ${legacy}`); }\ncatch (e) { if ((e as NodeJS.ErrnoException).code !== \"ENOENT\") throw e; }","typeGuard":null,"tryCatchPattern":"try {\n  await archiveSession(candidate);\n} catch (err) {\n  if (err instanceof Error && err.message.startsWith(\"archive destination exists:\")) {\n    // check both dest and legacy path from the message; remove or relocate stale files, then retry\n  } else throw err;\n}","preventionTips":["After upgrading omp, sweep archive directories for files matching the old naming scheme","Never manually decompress archives back into the sessions directory","Clean up partial archives from crashed runs before re-running GC"],"tags":["filesystem","archive","gc","collision"],"backgroundTag":"file-already-exists","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}