GitoxideLabs/gitoxide · error

cannot drop stashed commit

Error message

cannot drop stashed commit {}

What it means

During a history rewrite, tix updates stash references so they follow their rewritten commits. If a stashed commit was removed by the rewrite (it is in the `removed` set), there is no new location to point the stash reference at, so tix refuses rather than silently dropping the saved worktree state. The error names the short hash of the stashed commit that could not be migrated.

Solutions

  1. Unstash (apply) the saved worktree state for that commit before dropping it from history
  2. Remove the stash reference explicitly if the saved state is no longer needed, then re-run the rewrite
  3. Keep the commit in the rewritten history (don't mark it removed) so its stash can be migrated

Example fix

// before dropping the stash-owning commit
rewrite.remove(commit_id);
// after: restore the worktree state first
stash::restore_manual(path, bare, commit_id)?;
rewrite.remove(commit_id);
Defensive patterns

Strategy: try-catch

Validate before calling

let stashed: Vec<ObjectId> = stash_refs(&repo)?;
if stashed.iter().any(|id| rewrite.removed().contains(id)) {
    anyhow::bail!("a stash-owning commit is marked for removal; unstash it first");
}

Try / catch

match stash::rewrite_edits(&repo, plan) {
    Err(e) if e.to_string().starts_with("cannot drop stashed commit") => {
        // extract the id from the message, unstash it, then retry
    }
    other => other?,
}

Prevention

When it happens

Trigger: Calling `stash::rewrite_edits` (as part of a rewrite/rebase edit plan) when `rewritten` mapping plus a `removed` set indicate that a commit which owns a stash reference was dropped from the rewritten history.

Common situations: Dropping commits during an interactive rebase while those commits had associated tix stash state; amending histories where a stash-owning commit was filtered out.

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/5b1549df20e18181. Report an issue: GitHub.

Appendix: source

Thrown at gix-tix/src/edit/stash.rs:74

            Err(err) => {
                return Err(anyhow::anyhow!(
                    "could not inspect a stash reference before rebasing: {err}"
                ));
            }
        };
        let old = match associated_commit(reference.name().as_bstr()) {
            Ok(Some(id)) => id,
            Ok(None) => continue,
            Err(err) => {
                tracing::warn!(name = %reference.name(), error = %err, "ignored malformed tix stash reference");
                continue;
            }
        };
        let Some(new) = rewritten.get(&old).copied() else {
            continue;
        };
        if removed.contains(&old) {
            anyhow::bail!("cannot drop stashed commit {}", old.to_hex_with_len(7));
        }
        let new = new.context("a stashed commit cannot disappear during a rewrite")?;
        if new == old {
            continue;
        }
        if let Some(other) = destinations.insert(new, old) {
            anyhow::bail!(
                "stashes at {} and {} would converge on {}",
                other.to_hex_with_len(7),
                old.to_hex_with_len(7),
                new.to_hex_with_len(7)
            );
        }
        moves.push((reference.name().to_owned(), reference.target().into_owned(), old, new));
    }

    let mut forward = Vec::with_capacity(moves.len() * 2);
    let mut rollback = Vec::with_capacity(moves.len() * 2);

View on GitHub (pinned to e73179060b)