{"record":{"id":"af0a8b4d957751b9","repo":"gitbutlerapp/gitbutler","slug":"target-oid-must-exist-when-merge-check-is-enabled","errorCode":null,"errorMessage":"target OID must exist when merge check is enabled","messagePattern":"target OID must exist when merge check is enabled","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"crates/but/src/command/legacy/branch/list.rs","lineNumber":205,"sourceCode":"    let has_more_branches = branches_to_show.len() > max_branches;\n    let branches_to_show: Vec<_> = branches_to_show.into_iter().take(max_branches).collect();\n\n    // Calculate commits ahead if requested\n    let commits_ahead_map: Option<HashMap<String, usize>> = if ahead {\n        Some(calculate_commits_ahead(\n            ctx,\n            target_oid.expect(\"target OID must exist when ahead calculation is enabled\"),\n            &branches_to_show,\n        )?)\n    } else {\n        None\n    };\n\n    // Check merge status if requested\n    let merge_status_map: Option<HashMap<String, bool>> = if check_merge {\n        Some(check_branches_merge_cleanly(\n            ctx,\n            target_oid.expect(\"target OID must exist when merge check is enabled\"),\n            &applied_stacks,\n            &branches_to_show,\n        )?)\n    } else {\n        None\n    };\n\n    let allow_truncation = out.format().allows_truncation();\n    if let Some(out) = out.for_json() {\n        output_json(\n            &applied_stacks,\n            &branches_to_show,\n            has_more_branches,\n            &branch_review_map,\n            commits_ahead_map.as_ref(),\n            merge_status_map.as_ref(),\n            ctx,\n            out,","sourceCodeStart":187,"sourceCodeEnd":223,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/2497b8007aa4a1922dae9a805b32ffe5b5037785/crates/but/src/command/legacy/branch/list.rs#L187-L223","documentation":"Defensive expect in 'but branch list': the merge-status check (default on; disabled with --no-check) needs the workspace target's commit id to test whether branches merge cleanly into it. As with the ahead calculation, target_oid is resolved whenever '!empty || ahead || check_merge' holds and resolution failures propagate as errors before this point, so the expect is a wiring invariant rather than a reachable user-facing failure.","triggerScenarios":"Only a refactor that enables check_merge handling while resolving target_oid under a narrower condition than list.rs:47 uses; user input alone cannot trigger it.","commonSituations":"Contributors changing flag semantics around target resolution; end users instead hit the propagated 'target unresolved' error when the workspace base branch is missing.","solutions":["Update the resolution condition whenever a new flag consumes target_oid","Maintainer: convert to an ok_or_else error naming --check as the requiring flag","Cover the flag matrix (--no-check, --no-ahead, --empty) in CLI tests"],"exampleFix":"// before\ntarget_oid.expect(\"target OID must exist when merge check is enabled\")\n\n// after\nlet target_oid = target_oid.ok_or_else(|| {\n    anyhow::anyhow!(\"merge checking needs a resolvable workspace target branch; fetch the target ref first\")\n})?;","handlingStrategy":"validation","validationCode":"// Ensure sync of the merge-check consumer with target resolution\n// (unit-level: invoke the list handler with check_merge=true and a resolvable workspace)\nlet out = run_but(&[\"branch\", \"list\"]).assert().success();\nlet out_no_check = run_but(&[\"branch\", \"list\", \"--no-check\"]).assert().success();","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Treat '--no-check' as the immediate workaround when target resolution errors (not panics) appear","Keep the flag list that requires the target documented next to the resolution condition","Convert sibling expects to ok_or_else errors when touching this file"],"tags":["rust","panic","invariant","cli","merge-check","branch-list"],"backgroundTag":"missing-target-ref","analyzedSha":"2497b8007aa4a1922dae9a805b32ffe5b5037785","analyzedAt":"2026-08-17T00:30:25.648Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}