{"record":{"id":"152bbf5b36406a44","repo":"gitbutlerapp/gitbutler","slug":"non-empty-conflicts-map-contains-a-commit","errorCode":null,"errorMessage":"non-empty conflicts map contains a commit","messagePattern":"non-empty conflicts map contains a commit","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but/src/command/legacy/resolve.rs","lineNumber":1284,"sourceCode":"                    \"  {} {}\",\n                    t.important.paint(\"Branch:\"),\n                    t.local_branch.paint(branch_name)\n                )?;\n                for commit in commits {\n                    writeln!(\n                        human_out,\n                        \"    {} {} {}\",\n                        t.sym().dot.error(),\n                        t.hint.paint(&commit.commit_short_id),\n                        commit.commit_message\n                    )?;\n                }\n            }\n\n            let next_commit = resolution_queue\n                .first()\n                .copied()\n                .expect(\"non-empty conflicts map contains a commit\");\n            writeln!(\n                human_out,\n                \"Resolve the next commit with {}.\",\n                t.command_suggestion\n                    .paint(format!(\"but resolve {}\", next_commit.commit_short_id))\n            )?;\n        }\n    }\n\n    if let Some(json_out) = out.for_json() {\n        let conflicts_by_branch = conflicts_after\n            .iter()\n            .map(|(branch_name, commits)| {\n                (\n                    branch_name,\n                    commits\n                        .iter()\n                        .map(|commit| {","sourceCodeStart":1266,"sourceCodeEnd":1302,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/2497b8007aa4a1922dae9a805b32ffe5b5037785/crates/but/src/command/legacy/resolve.rs#L1266-L1302","documentation":"Invariant in the 'but resolve' output path: the code runs inside a block that only executes when at least one conflict was recorded for a branch, and it then takes the first commit of that branch's resolution queue to suggest the next 'but resolve <id>'. The expect fires if the per-branch queue is empty while the aggregate conflicts map is not - an internal desync between the two structures.","triggerScenarios":"Conflicts are recorded under a branch key whose resolution queue ended up empty after earlier steps consumed or filtered it; a refactor moves queue population so the map and queue are no longer filled together.","commonSituations":"Long-running resolve sessions resuming from persisted state; workspace updates landing between listing conflicts and printing suggestions.","solutions":["Re-run 'but resolve' (or its listing subcommand) to refresh conflict state from the workspace","Report the scenario - queue/map desync is an internal bug, not a user error","Maintainer: derive next_commit from the same iteration that printed the branch header instead of a second lookup"],"exampleFix":"// before\nlet next_commit = resolution_queue.first().copied()\n    .expect(\"non-empty conflicts map contains a commit\");\n\n// after\nlet Some(next_commit) = resolution_queue.first().copied() else {\n    tracing::warn!(branch = %branch_name, \"conflicts recorded but resolution queue empty\");\n    continue;\n};","handlingStrategy":"validation","validationCode":"// Keep the conflicts map and resolution queue in one structure so they cannot desync\nstruct BranchConflicts {\n    branch: BranchName,\n    queue: NonEmpty<ConflictedCommit>, // empty-by-construction is impossible\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Derive the suggested next commit from the same iteration that renders each branch block","Re-list conflicts before printing suggestions after any workspace mutation","Use NonEmpty containers for queues that accompany non-empty conflict maps"],"tags":["rust","panic","invariant","resolve","conflicts","cli"],"backgroundTag":"internal-invariant-panic","analyzedSha":"2497b8007aa4a1922dae9a805b32ffe5b5037785","analyzedAt":"2026-08-17T00:30:25.648Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}