Yeachan-Heo/oh-my-codex · error · Error
Native hook transaction rollback preserved ${artifact.path}
Error message
Native hook transaction rollback preserved ${artifact.path} for manual recovery because ${artifact.label} no longer matches the expected restored version. What it means
After rollback writes the pre-transaction bytes back to artifact.path, setup re-reads the file and verifies it matches the recorded before-state (bytes and topology such as link count / symlink status). A mismatch means the restore did not land as expected, so the file is preserved for manual recovery instead of silently accepted.
Source
Thrown at src/cli/setup.ts:1877
(stabilizedSnapshot) => {
applied.appliedSnapshot = stabilizedSnapshot;
},
assertRollbackState,
);
}
const restored = await assertNativeHookTransactionArtifactSnapshot(
artifact.path,
artifact.label,
applied.appliedSnapshot,
"rollback",
);
if (
!nativeHookTransactionSnapshotMatchesExpected(restored, {
bytes: artifact.before.bytes,
topology: artifact.before.topology,
})
) {
throw new Error(
`Native hook transaction rollback preserved ${artifact.path} for manual recovery because ${artifact.label} no longer matches the expected restored version.`,
);
}
}
async function cleanupNativeHookTransactionStagedDeletions(
applied: readonly AppliedNativeHookTransactionArtifact[],
ancestorPrecondition: NativeHookTransactionAncestorPrecondition,
tracker: RegularFileDurabilityTracker,
preconditions?: readonly NativeHookTransactionPrecondition[],
rollbackApplied?: readonly AppliedNativeHookTransactionArtifact[],
): Promise<void> {
for (const entry of applied) {
if (
!entry.stagedDeletionPath ||
!entry.stagedDeletionSnapshot ||
entry.stagedDeletionCleaned
) {View on GitHub (pinned to 3ad79a8a6f)
Solutions
- Manually compare artifact.path with the intended before-bytes recorded in the transaction log
- Stop concurrent writers and re-run setup
- Check for filesystem-level oddities (bind mounts, symlinks pointing at the path)
- Verify no test injection hooks fired during restore
Defensive patterns
Strategy: try-catch
Try / catch
try { await tx.rollback(); } catch (e) { if (e instanceof Error && e.message.includes("no longer matches the expected restored version")) { /* manually restore from backup root copy, then re-run setup */ } else throw e; } Prevention
- Prevent concurrent writers during the transaction window
- Verify restored files byte-for-byte after any manual recovery
- Re-run setup to confirm consistent state
When it happens
Trigger: Post-restore verification where the file on disk differs from artifact.before — e.g. another writer touched it immediately after restore, or topology (symlink/hardlink) diverged.
Common situations: Racing processes, platforms where rename/replace semantics differ (Windows), or fault injection at before_rollback checkpoints.
Related errors
- Native hook transaction rollback preserved ${artifact.path}
- Native hook transaction rollback removal claim failed (${err
- Native hook transaction backup verification failed for ${bac
- Native hook transaction failed (${message}) and rollback fai
- Native hook transaction failed and was rolled back: ${messag
AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27).
Data as JSON: /api/errors/ef92eda3bf3e9e7c.
Report an issue: GitHub.