Yeachan-Heo/oh-my-codex · critical · Error
${primaryMessage} (cancellation_rollback_failed:${rollbackFa
Error message
${primaryMessage} (cancellation_rollback_failed:${rollbackFailureCount}${sample}). What it means
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.
Source
Thrown at src/cli/index.ts:8710
for (const committedEntry of committed.reverse()) {
try {
if (cancellationTestRollbackFailureMode === committedEntry.mode) {
throw new Error(`Injected cancellation rollback failure for ${committedEntry.mode}.`);
}
await committedEntry.handle.truncate(0);
await committedEntry.handle.write(committedEntry.entry.originalContent, 0, "utf-8");
await committedEntry.handle.sync();
} catch {
rollbackFailureCount += 1;
if (rollbackFailureSample.length < 3) {
rollbackFailureSample.push(committedEntry.mode.replace(/[^A-Za-z0-9_-]/g, "_"));
}
}
}
if (rollbackFailureCount > 0) {
const primaryMessage = writeError instanceof Error ? writeError.message : String(writeError);
const sample = rollbackFailureSample.length > 0 ? `:${rollbackFailureSample.join(",")}` : "";
throw new Error(`${primaryMessage} (cancellation_rollback_failed:${rollbackFailureCount}${sample}).`, { cause: writeError });
}
throw writeError;
}
} finally {
await Promise.all(opened.map(({ handle }) => handle.close().catch(() => undefined)));
}
for (const mode of reported) {
console.log(`Cancelled: ${mode}`);
}
if (reported.size === 0) {
console.log("No active modes to cancel.");
}
} catch (err) {
logCliOperationFailure(err);
process.exitCode = 1;
}View on GitHub (pinned to 3ad79a8a6f)
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
Example fix
// before
await runOperation(opts); // Error: write failed (cancellation_rollback_failed:2:state/a.json:state/b.json)
// after
try {
await runOperation(opts);
} catch (e) {
if (/cancellation_rollback_failed/.test(String(e))) await verifyAndRepairState();
throw e;
} Defensive patterns
Strategy: fallback
Validate before calling
import { promises as fs } from "node:fs";
await fs.access(stateDir, fs.constants.W_OK);
// crude free-space check on POSIX
const stat = await fs.statfs ? fs.statfs(stateDir) : null;
if (stat && Number(stat.bavail) * Number(stat.bsize) < 50 * 1024 * 1024) {
throw new Error('Insufficient space for rollback safety');
} Type guard
function isRollbackFailure(e: unknown): e is Error & { cause: unknown } {
return e instanceof Error && /cancellation_rollback_failed/.test(e.message);
} Try / catch
try {
await runOperation(opts);
} catch (e) {
if (isRollbackFailure(e)) {
const [, count, sample] = e.message.match(/cancellation_rollback_failed:(\d+)(?::(.+))?\./) ?? [];
await repairState(sample ? sample.split(',') : []); // restore listed paths from backup/journal
}
throw e;
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Refusing cancellation because state content changed: ${chang
- canonical_scale_up_rollback_resolved_membership_verification
- preLaunch ${completion.operation} failed
- detached leader authority missing before rollback
- Refusing cancellation because detached run authority is inva
AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27).
Data as JSON: /api/errors/89be6d264074c6f4.
Report an issue: GitHub.