{"record":{"id":"89be6d264074c6f4","repo":"Yeachan-Heo/oh-my-codex","slug":"primarymessage-cancellation-rollback-failed","errorCode":null,"errorMessage":"${primaryMessage} (cancellation_rollback_failed:${rollbackFailureCount}${sample}).","messagePattern":"(.+?) \\(cancellation_rollback_failed:(.+?)(.+?)\\)\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"src/cli/index.ts","lineNumber":8710,"sourceCode":"        for (const committedEntry of committed.reverse()) {\n          try {\n            if (cancellationTestRollbackFailureMode === committedEntry.mode) {\n              throw new Error(`Injected cancellation rollback failure for ${committedEntry.mode}.`);\n            }\n            await committedEntry.handle.truncate(0);\n            await committedEntry.handle.write(committedEntry.entry.originalContent, 0, \"utf-8\");\n            await committedEntry.handle.sync();\n          } catch {\n            rollbackFailureCount += 1;\n            if (rollbackFailureSample.length < 3) {\n              rollbackFailureSample.push(committedEntry.mode.replace(/[^A-Za-z0-9_-]/g, \"_\"));\n            }\n          }\n        }\n        if (rollbackFailureCount > 0) {\n          const primaryMessage = writeError instanceof Error ? writeError.message : String(writeError);\n          const sample = rollbackFailureSample.length > 0 ? `:${rollbackFailureSample.join(\",\")}` : \"\";\n          throw new Error(`${primaryMessage} (cancellation_rollback_failed:${rollbackFailureCount}${sample}).`, { cause: writeError });\n        }\n        throw writeError;\n      }\n    } finally {\n      await Promise.all(opened.map(({ handle }) => handle.close().catch(() => undefined)));\n    }\n\n    for (const mode of reported) {\n      console.log(`Cancelled: ${mode}`);\n    }\n\n    if (reported.size === 0) {\n      console.log(\"No active modes to cancel.\");\n    }\n  } catch (err) {\n    logCliOperationFailure(err);\n    process.exitCode = 1;\n  }","sourceCodeStart":8692,"sourceCodeEnd":8728,"githubUrl":"https://github.com/Yeachan-Heo/oh-my-codex/blob/3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2/src/cli/index.ts#L8692-L8728","documentation":"While rolling back already-opened files after a write failure during cancellation, one or more rollback writes themselves failed. The original write error is rethrown, annotated with cancellation_rollback_failed:<count> plus the paths (sample) of files that could not be restored, so the user knows the state directory is now partially inconsistent.","triggerScenarios":"A write fails mid-cancellation, then during the rollback loop an ftruncate/write on an already-opened handle throws (ENOSPC, EIO, file truncated externally, permissions changed). rollbackFailureCount > 0 and the aggregate error is thrown instead of the bare writeError.","commonSituations":"Full disk (ENOSPC) while restoring files; NFS/network filesystem write errors; antivirus or security software locking handles on Windows; external truncation of state files between open and rollback.","solutions":["Check disk space and filesystem health (df -h, dmesg for I/O errors) on the state directory","Verify no other process holds/locks the state files (lsof, antivirus exclusions)","Inspect the sampled paths in the message and manually restore them from backup/journal","Retry the operation from a clean state after freeing space; validate state integrity afterwards"],"exampleFix":"// before\nawait runOperation(opts); // Error: write failed (cancellation_rollback_failed:2:state/a.json:state/b.json)\n\n// after\ntry {\n  await runOperation(opts);\n} catch (e) {\n  if (/cancellation_rollback_failed/.test(String(e))) await verifyAndRepairState();\n  throw e;\n}","handlingStrategy":"fallback","validationCode":"import { promises as fs } from \"node:fs\";\nawait fs.access(stateDir, fs.constants.W_OK);\n// crude free-space check on POSIX\nconst stat = await fs.statfs ? fs.statfs(stateDir) : null;\nif (stat && Number(stat.bavail) * Number(stat.bsize) < 50 * 1024 * 1024) {\n  throw new Error('Insufficient space for rollback safety');\n}","typeGuard":"function isRollbackFailure(e: unknown): e is Error & { cause: unknown } {\n  return e instanceof Error && /cancellation_rollback_failed/.test(e.message);\n}","tryCatchPattern":"try {\n  await runOperation(opts);\n} catch (e) {\n  if (isRollbackFailure(e)) {\n    const [, count, sample] = e.message.match(/cancellation_rollback_failed:(\\d+)(?::(.+))?\\./) ?? [];\n    await repairState(sample ? sample.split(',') : []); // restore listed paths from backup/journal\n  }\n  throw e;\n}","preventionTips":["Keep backups or an append-only journal of state files before bulk writes","Monitor disk space before long write transactions","Run integrity verification after any failed cancellation"],"tags":["rollback","write-failure","disk-full","consistency","cancellation"],"backgroundTag":"transaction-rollback-failure","analyzedSha":"3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2","analyzedAt":"2026-08-27T22:18:39.783Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}