{"record":{"id":"64ac40f060718a6d","repo":"gitbutlerapp/gitbutler","slug":"failed-to-land-branch-onto-target-display","errorCode":null,"errorMessage":"Failed to land {branch} onto {target_display}","messagePattern":"Failed to land (.+?) onto (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but-api/src/land/mod.rs","lineNumber":315,"sourceCode":"            {\n                fetch_target_remote(ctx, &fetch_remote_name)?;\n            }\n            Err(err) if deliver::is_retryable_concurrency_error(&err) => {\n                return Err(err.context(format!(\n                    \"Target branch kept moving; fetched and retried {MAX_PUSH_ATTEMPTS} times\"\n                )));\n            }\n            Err(err) if update_target_locally => {\n                return Err(err.context(\"Failed to update local target branch\"));\n            }\n            Err(err) => return Err(err.context(\"Failed to push to target branch\")),\n        }\n    }\n\n    let Some(landed) = landed else {\n        // The loop only exits without a result when every attempt hit a retryable race; that path\n        // already returned an error above, so this is unreachable in practice.\n        bail!(\"Failed to land {branch} onto {target_display}\");\n    };\n\n    // On the real-remote path, re-fetch so the tracking ref reflects the landed commit, then verify\n    // it actually advanced before reconciling — otherwise the reconcile would be a silent no-op.\n    if let BranchLandKind::Updated { new_target_oid, .. } = &landed\n        && !update_target_locally\n    {\n        fetch_target_remote(ctx, &fetch_remote_name)?;\n\n        // A concurrent push may have moved the tip *past* our commit, which still counts as the\n        // target having advanced to include what we landed — so test reachability, not equality.\n        let advanced = {\n            let repo = ctx.repo.get()?;\n            match peel_target_tip(&repo, &fetch_remote_name, &target_branch_name)? {\n                Some(tip) => target_ref_contains(&repo, *new_target_oid, tip)?,\n                None => false,\n            }\n        };","sourceCodeStart":297,"sourceCodeEnd":333,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/58e5313667b857ef39a730e380af31816a7b1768/crates/but-api/src/land/mod.rs#L297-L333","documentation":"This is the fallback message thrown by `branch_land` (crates/but-api/src/land/mod.rs:315) after the push/retry loop finishes without producing a `LandOutcome`. The loop normally exits via fast-forward/merge/already-integrated success or via a concrete push error, so this arm is an internal invariant violation: the landing machinery exhausted its attempts without recording a result or an error. It means GitButler could not determine any landing outcome for the branch onto the target ref.","triggerScenarios":"Calling `branch_land` (or `but land <branch>`) when the internal push loop exits without setting `landed` — theoretically only reachable if every `MAX_PUSH_ATTEMPTS` attempts hit a retryable concurrency race and the guard above failed to fire, i.e. an unreachable-in-practice defensive bail.","commonSituations":"Hitting a persistent race where the target branch is being moved concurrently (e.g. CI or a teammate pushing to the same base branch during every retry); running an older/patched build where the retry-limit guard behaves differently; internal bugs in the land loop.","solutions":["Retry the `but land` command — the target may have stabilized since the race window.","Fetch the target remote (`but pull` / `git fetch`) so the local tracking ref is current, then retry landing.","Check the target branch for concurrent automation (CI merges, bots) and pause it while landing.","If it reproduces consistently, report a bug — this path is documented as unreachable in practice (internal invariant violation)."],"exampleFix":"// before\nbut land feature-x --to main   // fails: Failed to land feature-x onto origin/main\n// after\ngit fetch origin && but pull && but land feature-x --to main","handlingStrategy":"retry","validationCode":"null","typeGuard":"null","tryCatchPattern":"// TypeScript (Tauri/SDK caller)\ntry {\n  await api.branchLand({ branch, target });\n} catch (e) {\n  if (String(e).includes('Failed to land')) {\n    await api.fetchTarget(); // refresh tracking refs, then retry once\n    await api.branchLand({ branch, target });\n  }\n}","preventionTips":["Pause CI merges and bots that push to the target branch while landing.","Fetch the target remote immediately before landing to minimize the race window.","Treat repeated occurrences as a bug report against the land loop, not a user error."],"tags":["git","push","race-condition","internal-error"],"backgroundTag":"internal-invariant-violation","analyzedSha":"58e5313667b857ef39a730e380af31816a7b1768","analyzedAt":"2026-09-18T06:50:32.052Z","contentChangedAt":"2026-09-18T06:50:32.052Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}