gitbutlerapp/gitbutler · error

Expected target tip selector to point to a pick

Error message

Expected target tip selector to point to a pick

What it means

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.

Solutions

  1. Verify the selector was derived from the current editor plan (after any rewrites) and points at a Pick step
  2. 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
  3. Recompute the target-tip selector after any plan mutation rather than caching it
  4. Report/inspect the editor step list (editor.lookup_step) to see what the selector actually points at

Example fix

// before: assuming the selector is a pick
preserve_pick_parents(editor, selector)?;
// after: validate the step kind first
match editor.lookup_step(selector)? {
    Step::Pick(_) => preserve_pick_parents(editor, selector)?,
    other => anyhow::bail!("target tip selector points at {:?}, not a pick", other),
}
Defensive patterns

Strategy: validation

Validate before calling

let step = editor.lookup_step(selector)?;
if !matches!(step, Step::Pick(_)) {
    anyhow::bail!("selector must point at a Pick step");
}

Type guard

fn is_pick(step: &Step) -> bool { matches!(step, Step::Pick(_)) }

Try / catch

match integrate_upstream_with_hints(...) {
    Err(e) if e.to_string().contains("point to a pick") => recompute_selector_and_retry(),
    r => r,
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of gitbutlerapp/gitbutler@58e5313667 (2026-09-18). Data as JSON: /api/errors/256c96e121086a2f. Report an issue: GitHub.

Appendix: source

Thrown at crates/but-workspace/src/upstream_integration.rs:1162

            child: head_ref_selector,
            parent: head_ref_selector,
        },
        SelectorSet::All,
        SelectorSet::All,
        false,
    )?;
    preserve_pick_parents(editor, target_tip_selector)?;
    editor.add_edge(head_ref_selector, target_tip_selector, 0)?;

    Ok((head_ref_selector, fallback_ref_name))
}

fn preserve_pick_parents<M: RefMetadata>(
    editor: &mut Editor<'_, '_, M>,
    selector: Selector,
) -> Result<()> {
    let Step::Pick(mut pick) = editor.lookup_step(selector)? else {
        bail!("Expected target tip selector to point to a pick");
    };
    let commit = editor.find_commit(pick.id)?;
    // TODO: Teach but-rebase to treat immutable reference parents as object
    // anchors. Until then, preserve the target tip's original parents here so
    // graph-rebase materializes the fallback branch at the exact target ref
    // object instead of replaying merge-based target history into an equivalent
    // local rewrite.
    pick.preserved_parents = Some(commit.inner.parents.iter().copied().collect());
    editor.replace(selector, Step::Pick(pick))?;
    Ok(())
}

/// Fast-forward the local branch that tracks a remote `target_ref`, preferring the same name.
///
/// Local target refs, missing tracking branches, checked-out branches, and non-fast-forward updates
/// are left unchanged.
pub fn fast_forward_local_tracking_branch(
    repo: &gix::Repository,

View on GitHub (pinned to 58e5313667)