GitoxideLabs/gitoxide · error

has a pending rebase

Error message

{label} has a pending rebase

What it means

`review::start` refuses to begin a review when either the reviewed commit (`tip`) or the review `base` is currently part of a pending rebase: `super::rebase::is_pending(&commit)` is checked for both (`"reviewed commit"`, `"review base"`) and the failing label is interpolated into `{label} has a pending rebase`. Editing commits mid-rebase would produce unstable review content.

Solutions

  1. Wait for the rebase to complete, then start the review against the finalized commits.
  2. Abort the pending rebase and start the review on stable history.
  3. Choose a different base/tip pair outside the pending rebase range.
  4. Detect pending state up front and defer the review (e.g. re-run the trigger after the rebase finishes).

Example fix

// before: review during an in-progress rebase
review::start(repo, base_id, tip_id)?; // bails: "{label} has a pending rebase"
// after: defer until the commits are settled
for id in [base_id, tip_id] {
    let c = repo.find_commit(id)?.decode()?.into_owned()?;
    if rebase::is_pending(&c) { return Err(defer_review_until_rebase_done(id)); }
}
review::start(repo, base_id, tip_id)?;
Defensive patterns

Strategy: validation

Validate before calling

for (label, id) in [("reviewed commit", tip_id), ("review base", base_id)] {
    let c = repo.find_commit(id)?.decode()?.into_owned()?;
    if gix_tix::edit::rebase::is_pending(&c) {
        // defer review until the rebase involving {label} completes
    }
}

Type guard

fn reviewable(repo: &gix::Repository, id: ObjectId) -> anyhow::Result<bool> {
    Ok(!gix_tix::edit::rebase::is_pending(&repo.find_commit(id)?.decode()?.into_owned()?))
}

Prevention

When it happens

Trigger: Calling `review::start` where decoding `tip` or `base` yields a commit for which `rebase::is_pending` is true — i.e. either endpoint is a provisional commit of an in-progress rebase.

Common situations: Starting a review while an interactive rebase is paused; automation triggered on commits that are temporarily rewritten during a rebase; reviewing the base commit that itself is being rebased.

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/15ee976e7a81cfe4. Report an issue: GitHub.

Appendix: source

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

) -> Result<Started> {
    let repo = open_repository(repository_path, bare, false).context("could not open repository to start review")?;
    let workdir = repo.workdir().context("review requires a worktree")?.to_owned();
    let head = repo.head().context("could not read HEAD before review")?;
    let restore = (
        head.referent_name().map(ToOwned::to_owned),
        head.id().map(gix::Id::detach),
    );
    if tip == base || !graph.is_ancestor(base, tip) {
        anyhow::bail!("the review base must be an ancestor of the reviewed commit");
    }
    for (label, id) in [("reviewed commit", tip), ("review base", base)] {
        let commit = repo
            .find_commit(id)
            .with_context(|| format!("could not find {label}"))?
            .decode()?
            .into_owned()?;
        if super::rebase::is_pending(&commit) {
            anyhow::bail!("{label} has a pending rebase");
        }
    }
    ensure_clean(&workdir)?;

    let departure_pin = match restore.1 {
        Some(id) => {
            let target = restore.0.clone().map_or(Target::Object(id), Target::Symbolic);
            Some((
                super::time_travel::create_pin(&repo, target, id, "tix review departure")?,
                true,
            ))
        }
        None => None,
    };

    let name = next_reference(&repo)?;
    let mut commit = gix::objs::Commit {
        tree: repo.find_commit(base)?.tree_id()?.detach(),

View on GitHub (pinned to e73179060b)