GitoxideLabs/gitoxide · error

the review return reference no longer descends from the…

Error message

the review return reference no longer descends from the reviewed commit

What it means

During finish, the stored review return reference is resolved and validated: it must still be a descendant of the reviewed commit (tip). If the reference resolves to a commit that no longer descends from the tip, the return point has diverged and the review cannot safely be finished onto it.

Solutions

  1. Move the return reference back onto a commit descending from the review tip, or fast-forward it.
  2. Supply an explicit valid fallback commit via the fallback parameter instead of relying on the stale reference.
  3. Inspect the return branch (`git log <return-ref>`) and rebase or reset it to re-include the reviewed work.

Example fix

// before: return ref diverged, finish fails
review::finish(repo, graph, review_id, None)?;
// after: pass a known-good descendant explicitly
review::finish(repo, graph, review_id, Some(current_branch_tip))?;
Defensive patterns

Strategy: validation

Validate before calling

if let Some(name) = return_ref {
    let id = repo.try_find_reference(name.as_ref())?.context("missing return ref")?.peel_to_id()?.detach();
    if !graph.is_ancestor(review_tip, id) {
        return Err(anyhow::anyhow!("return ref diverged; rebase or reset it before finishing"));
    }
}

Prevention

When it happens

Trigger: Calling `finish_with_progress` with no fallback while the return reference (return_to / legacy reattach name) has been moved, rebased, or reset so it no longer contains the review tip.

Common situations: The branch recorded as the return point was force-pushed or rebased while the review was active; the user reset the return branch backwards; history rewriting tools moved the return branch onto an unrelated line.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of GitoxideLabs/gitoxide@e73179060b (2026-09-08). Data as JSON: /api/errors/729c503819ebd567. Report an issue: GitHub.

Appendix: source

Thrown at gix-tix/src/edit/review.rs:279

        }
        Some((id, None))
    } else {
        return_name
            .map(|name| {
                let Some(mut reference) = repo.try_find_reference(name.as_ref())? else {
                    return Ok(None);
                };
                let checkout_reference = if name.as_bstr().starts_with(history::PIN_PREFIX) {
                    reference.target().try_name().map(ToOwned::to_owned)
                } else {
                    Some(name)
                };
                let id = reference
                    .peel_to_id()
                    .context("the review return reference does not resolve")?
                    .detach();
                if !graph.is_ancestor(tip, id) {
                    anyhow::bail!("the review return reference no longer descends from the reviewed commit");
                }
                Ok(Some((id, checkout_reference)))
            })
            .transpose()?
            .flatten()
    };
    if fallback.is_none() && has_return && checkout.is_none() {
        return Ok(Finish::SelectReturn { tip });
    }
    for (label, id) in [("reviewed commit", tip), ("review base", base)] {
        let endpoint = repo.find_commit(id)?.decode()?.into_owned()?;
        if super::rebase::is_pending(&endpoint) {
            anyhow::bail!("{label} has a pending rebase");
        }
    }
    match super::rebase::finish_review_with_progress(
        &repo,
        graph,

View on GitHub (pinned to e73179060b)