{"record":{"id":"256c96e121086a2f","repo":"gitbutlerapp/gitbutler","slug":"expected-target-tip-selector-to-point-to-a-pick","errorCode":null,"errorMessage":"Expected target tip selector to point to a pick","messagePattern":"Expected target tip selector to point to a pick","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but-workspace/src/upstream_integration.rs","lineNumber":1162,"sourceCode":"            child: head_ref_selector,\n            parent: head_ref_selector,\n        },\n        SelectorSet::All,\n        SelectorSet::All,\n        false,\n    )?;\n    preserve_pick_parents(editor, target_tip_selector)?;\n    editor.add_edge(head_ref_selector, target_tip_selector, 0)?;\n\n    Ok((head_ref_selector, fallback_ref_name))\n}\n\nfn preserve_pick_parents<M: RefMetadata>(\n    editor: &mut Editor<'_, '_, M>,\n    selector: Selector,\n) -> Result<()> {\n    let Step::Pick(mut pick) = editor.lookup_step(selector)? else {\n        bail!(\"Expected target tip selector to point to a pick\");\n    };\n    let commit = editor.find_commit(pick.id)?;\n    // TODO: Teach but-rebase to treat immutable reference parents as object\n    // anchors. Until then, preserve the target tip's original parents here so\n    // graph-rebase materializes the fallback branch at the exact target ref\n    // object instead of replaying merge-based target history into an equivalent\n    // local rewrite.\n    pick.preserved_parents = Some(commit.inner.parents.iter().copied().collect());\n    editor.replace(selector, Step::Pick(pick))?;\n    Ok(())\n}\n\n/// Fast-forward the local branch that tracks a remote `target_ref`, preferring the same name.\n///\n/// Local target refs, missing tracking branches, checked-out branches, and non-fast-forward updates\n/// are left unchanged.\npub fn fast_forward_local_tracking_branch(\n    repo: &gix::Repository,","sourceCodeStart":1144,"sourceCodeEnd":1180,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/58e5313667b857ef39a730e380af31816a7b1768/crates/but-workspace/src/upstream_integration.rs#L1144-L1180","documentation":"During upstream integration, preserve_pick_parents expects the selector given by the caller to point at a Step::Pick in the rebase editor. If lookup_step returns any other step kind, the operation cannot preserve the target tip's original parents and the library bails.","triggerScenarios":"integrate_upstream_with_hints or replace_checkout_ref_with_fallback passing a target tip selector that resolves to a non-Pick step (e.g. a CheckOut/exec step or an empty/removed step) in the editor's step list.","commonSituations":"Integrating a target branch whose tip was materialized as a checkout/fallback rather than a pick, or stale selectors computed before the rebase plan was rewritten, so the selector no longer points at the pick that represented the target tip.","solutions":["Verify the selector was derived from the current editor plan (after any rewrites) and points at a Pick step","Check that the target tip commit was actually added as a pick during plan construction; if the target is a merge/checkout fallback, pass a selector to the fallback step instead","Recompute the target-tip selector after any plan mutation rather than caching it","Report/inspect the editor step list (editor.lookup_step) to see what the selector actually points at"],"exampleFix":"// before: assuming the selector is a pick\npreserve_pick_parents(editor, selector)?;\n// after: validate the step kind first\nmatch editor.lookup_step(selector)? {\n    Step::Pick(_) => preserve_pick_parents(editor, selector)?,\n    other => anyhow::bail!(\"target tip selector points at {:?}, not a pick\", other),\n}","handlingStrategy":"validation","validationCode":"let step = editor.lookup_step(selector)?;\nif !matches!(step, Step::Pick(_)) {\n    anyhow::bail!(\"selector must point at a Pick step\");\n}","typeGuard":"fn is_pick(step: &Step) -> bool { matches!(step, Step::Pick(_)) }","tryCatchPattern":"match integrate_upstream_with_hints(...) {\n    Err(e) if e.to_string().contains(\"point to a pick\") => recompute_selector_and_retry(),\n    r => r,\n}","preventionTips":["Recompute target-tip selectors after any rebase-plan mutation","Never cache selectors across plan rewrites","Assert the step kind at selection time, not at use time","Log the editor step list when selector resolution fails"],"tags":["git","rebase","selector","internal-invariant"],"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"}