Yeachan-Heo/oh-my-codex · critical · Error

Native hook transaction committed but staged deletion cleanu

Error message

Native hook transaction committed but staged deletion cleanup failed during finalization: ${error instanceof Error ? error.message : String(error)}

What it means

After a native hook transaction commits and staged-deletion cleanup has already run for at least one artifact, a later finalization failure cannot be safely rolled back (cleanup already deleted the pre-states). This error surfaces that the commit stands but finalization did not complete, wrapping the underlying error.

Source

Thrown at src/cli/setup.ts:2086

		await cleanupNativeHookTransactionStagedDeletions(
			applied,
			ancestorPrecondition,
			tracker,
			preconditions,
		);
		injectNativeHookTransactionFailure(
			"after_staged_cleanup",
			artifacts[artifacts.length - 1],
		);
		await assertUnmutatedNativeHookTransactionPreconditions(preconditions, applied);
		await assertNativeHookTransactionAncestorPrecondition(ancestorPrecondition);
		await assertAppliedNativeHookTransactionSnapshots(applied);
	} catch (error) {
		if (
			stagedCleanupStarted &&
			applied.some((entry) => entry.stagedDeletionCleaned)
		) {
			throw new Error(
				`Native hook transaction committed but staged deletion cleanup failed during finalization: ${error instanceof Error ? error.message : String(error)}`,
			);
		}
		const rollbackFailures: string[] = [];
		const restored: AppliedNativeHookTransactionArtifact[] = [];
		try {
			await assertNativeHookTransactionRollbackState(applied);
		} catch (rollbackError) {
			rollbackFailures.push(
				`recovery preflight: ${rollbackError instanceof Error ? rollbackError.message : String(rollbackError)}`,
			);
		}
		if (rollbackFailures.length === 0) {
			for (const entry of [...applied].reverse()) {
				try {
					await assertNativeHookTransactionRollbackState(applied);
					await restoreNativeHookTransactionArtifact(
						entry,

View on GitHub (pinned to 3ad79a8a6f)

Solutions

  1. Treat the transaction as committed; do NOT attempt manual rollback of already-cleaned artifacts
  2. Read the wrapped error message to find the finalization step that failed and address it
  3. Re-run setup to converge to the desired end state
  4. Check that no external process modified hook files during finalization
Defensive patterns

Strategy: try-catch

Try / catch

try { await tx.finalize(); } catch (e) { if (e instanceof Error && e.message.includes("committed but staged deletion cleanup failed")) { /* treat as committed; fix wrapped finalization error; re-run setup */ } else throw e; }

Prevention

When it happens

Trigger: assertAppliedNativeHookTransactionSnapshots (or another finalization step) throws after stagedCleanupStarted and some entries have stagedDeletionCleaned set.

Common situations: Post-commit verification racing external file edits, or fault injection after the no-rollback point in tests.

Related errors


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