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

  1. Check disk space and filesystem health (df -h, dmesg for I/O errors) on the state directory
  2. Verify no other process holds/locks the state files (lsof, antivirus exclusions)
  3. Inspect the sampled paths in the message and manually restore them from backup/journal
  4. 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

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


AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27). Data as JSON: /api/errors/89be6d264074c6f4. Report an issue: GitHub.