{"record":{"id":"8dd92b934fc6c316","repo":"Yeachan-Heo/oh-my-codex","slug":"native-hook-transaction-failed-message-and-ro","errorCode":null,"errorMessage":"Native hook transaction failed (${message}) and rollback failed; manual recovery is required (${rollbackFailures.join(\"; \")}).","messagePattern":"Native hook transaction failed \\((.+?)\\) and rollback failed; manual recovery is required \\((.+?)\\)\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"src/cli/setup.ts","lineNumber":2137,"sourceCode":"\t\t\ttry {\n\t\t\t\tawait assertNativeHookTransactionRollbackState(applied);\n\t\t\t\tawait cleanupNativeHookTransactionStagedDeletions(\n\t\t\t\t\trestored,\n\t\t\t\t\tancestorPrecondition,\n\t\t\t\t\ttracker,\n\t\t\t\t\tundefined,\n\t\t\t\t\tapplied,\n\t\t\t\t);\n\t\t\t\tawait assertNativeHookTransactionRollbackState(applied);\n\t\t\t} catch (cleanupError) {\n\t\t\t\trollbackFailures.push(\n\t\t\t\t\t`staged deletion cleanup: ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\tif (rollbackFailures.length > 0) {\n\t\t\tthrow new Error(\n\t\t\t\t`Native hook transaction failed (${message}) and rollback failed; manual recovery is required (${rollbackFailures.join(\"; \")}).`,\n\t\t\t);\n\t\t}\n\t\tthrow new Error(`Native hook transaction failed and was rolled back: ${message}`);\n\t}\n}\n\n\nasync function ensureBackup(\n\tdestinationPath: string,\n\tcontentChanged: boolean,\n\tbackupContext: SetupBackupContext,\n\toptions: Pick<SetupOptions, \"dryRun\" | \"verbose\">,\n): Promise<boolean> {\n\tif (!contentChanged || !existsSync(destinationPath)) return false;\n\n\tconst relativePath = relative(backupContext.baseRoot, destinationPath);\n\tconst safeRelativePath =","sourceCodeStart":2119,"sourceCodeEnd":2155,"githubUrl":"https://github.com/Yeachan-Heo/oh-my-codex/blob/3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2/src/cli/setup.ts#L2119-L2155","documentation":"When a native hook transaction fails, setup attempts full rollback. If any rollback step also fails, the collected rollbackFailures are joined with the original error so the user knows the system is left in a partially applied state requiring manual recovery.","triggerScenarios":"An apply-phase error (e.g. 380/381/383-style failures) followed by at least one failed rollback step — restore errors, claim errors, or staged-deletion cleanup errors recorded in rollbackFailures.","commonSituations":"Permission or disk problems affecting both apply and rollback, concurrent interference during the whole transaction window, or multi-point fault injection in tests.","solutions":["Parse the semicolon-joined rollbackFailures list to enumerate every file needing manual attention","Manually restore each affected hooks.json/config.toml from the backup copies under the backup root","Fix environmental causes (permissions, disk space, concurrent processes)","Re-run setup once files are reconciled"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try { await tx.apply(); } catch (e) { if (e instanceof Error && e.message.includes(\"rollback failed; manual recovery is required\")) { const failures = e.message.match(/\\((.*)\\)\\.?$/)?.[1]?.split(\"; \") ?? []; for (const f of failures) await recoverManually(f); } else throw e; }","preventionTips":["Guarantee permissions/disk health before transactions","Prevent concurrent access to hook files during setup","Keep the backup root intact — it is the recovery source"],"tags":["transaction","rollback","recovery","manual-intervention"],"backgroundTag":"transaction-rollback-failed","analyzedSha":"3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2","analyzedAt":"2026-08-27T22:18:39.783Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}