{"record":{"id":"1b01461f28594db0","repo":"gitbutlerapp/gitbutler","slug":"rebase-is-always-some","errorCode":null,"errorMessage":"rebase is always Some(_)","messagePattern":"rebase is always Some\\(_\\)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"crates/but-transaction/src/lib.rs","lineNumber":155,"sourceCode":"        let callback_outcome = match callback_outcome {\n            Ok(outcome) => outcome,\n            Err(err) => {\n                inner.pending_ref_changes.rollback(&repo)?;\n                return Err(err);\n            }\n        };\n\n        let Inner {\n            mut rebase,\n            commit_mappings: _,\n            pending_metadata_removals,\n            pending_metadata_updates,\n            pending_created_independent_refs,\n            mut pending_ref_changes,\n            context_lines: _,\n            materialize_without_checkout,\n        } = inner;\n        let rebase = rebase.take().expect(\"rebase is always Some(_)\");\n\n        let should_rollback = callback_outcome.should_rollback();\n        // A rolled-back transaction never materializes, so it has no workspace to report.\n        let workspace = if should_rollback {\n            Ok(None)\n        } else {\n            workspace_state_from_rebase(\n                rebase,\n                &repo,\n                pending_metadata_removals,\n                pending_metadata_updates,\n                pending_created_independent_refs,\n                dry_run,\n                matches!(\n                    materialize_without_checkout,\n                    MaterializeWithoutCheckout::Yes\n                ),\n            )","sourceCodeStart":137,"sourceCodeEnd":173,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/caf1f223d3cfb94488c9198ad34487c6006c648f/crates/but-transaction/src/lib.rs#L137-L173","documentation":"An internal invariant panic in but-transaction: Inner::rebase is constructed as Some(rebase) and, apart from this take(), nothing clears it, so destructuring expects it to still be present at transaction commit time. Hitting this means the transaction machinery was driven in an unsupported way (the rebase was consumed/absented before finish) — i.e., a library bug or an API misuse, not a user-data problem.","triggerScenarios":"A code path between Transaction construction and outcome processing that takes/None-out inner.rebase (new misuse of the Transaction API), or a regression that moved the take() earlier; triggered by any workspace operation run through the transaction wrapper.","commonSituations":"Contributors adding a method on Transaction that also takes `rebase`; refactors that changed the Inner lifecycle; extremely rare in released builds.","solutions":["If you develop against these crates: audit your changes for any extra `inner.rebase.take()`/move of the rebase field before commit processing.","Downgrade to the last known-good build to confirm the invariant holds there.","For released builds, capture the panic backtrace and repository state and report it as a bug against but-transaction.","Retry the operation after a fresh app/process start; if it reproduces deterministically, the transaction state for that workspace is likely hitting the buggy path every time."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// process-level: this is a panic, not a Result — catch_unwind in Rust hosts,\n// or in Node capture the napi error and restart the worker/session:\ntry {\n  await api.runWorkspaceOperation(...);\n} catch (e) {\n  if (String(e?.message).includes('rebase is always Some')) {\n    await restartAppSession(); // recover process state, then report the bug\n  }\n  throw e;\n}","preventionTips":["Contributors: never add a second take()/move of inner.rebase; keep the single one at the destructuring site.","Pin to the last known-good release when this appears after an upgrade.","Always attach the backtrace and repro steps when reporting — it is an invariant breach, not user error."],"tags":["rust","internal-invariant","panic","transaction","bug"],"backgroundTag":"internal-invariant-violation","analyzedSha":"caf1f223d3cfb94488c9198ad34487c6006c648f","analyzedAt":"2026-08-20T07:55:40.983Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}