GitoxideLabs/gitoxide · error
already has saved worktree state
Error message
{} already has saved worktree state What it means
A tix stash reference is named after the commit at which state was saved, so at most one saved worktree state can exist per commit. This error fires when `save_manual` finds an existing reference under that commit's stash name, meaning a stash already exists for this commit and creating another would overwrite it. It reports the short hash of the commit.
Solutions
- Restore (`unstash`) the existing saved state first, then make the new stash
- Delete the existing stash reference if its saved state is no longer needed
- Check for an existing stash (e.g. via `find`/`try_find_reference` with `reference(id)`) before saving
Example fix
// before blind re-stash
stash::save_manual(path, bare, workdir, head_id)?;
// after: clear existing stash for this commit first
let name = tix::edit::stash::reference(head_id)?;
if repo.try_find_reference(name.as_ref())?.is_some() {
tix::edit::stash::restore_manual(path, bare, head_id)?;
}
stash::save_manual(path, bare, workdir, head_id)?; Defensive patterns
Strategy: validation
Validate before calling
let name = tix::edit::stash::reference(id)?;
let repo = gix::open(path)?;
let exists = repo.try_find_reference(name.as_ref())?.is_some();
if exists {
anyhow::bail!("a stash already exists for {}; restore or delete it first", id);
} Type guard
fn has_saved_state(repo: &gix::Repository, id: ObjectId) -> bool {
let name = tix::edit::stash::reference(id).expect("valid id");
repo.try_find_reference(name.as_ref()).map(|r| r.is_some()).unwrap_or(false)
} Prevention
- Check for an existing stash reference before every save
- Always restore or delete a stash before stashing the same commit again
- Avoid re-running stash scripts without cleanup logic
When it happens
Trigger: Calling `stash::save_manual` twice at the same HEAD commit without restoring/deleting the first stash; restoring a repo where an earlier tix stash session left a reference for the current HEAD.
Common situations: Repeated `tix stash` at the same commit; forgetting a previous stash after a failed restore; re-running a script that stashes idempotently.
Understand the failure class
Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.
Related errors
- tix stash reference does not use a canonical full commit ID
- rewritten commit already has saved worktree state
- could not inspect a stash reference before rebasing
- change ID is ambiguous in the Tix view; candidates
- cannot drop stashed commit
AI-assisted analysis of GitoxideLabs/gitoxide@e73179060b (2026-09-08).
Data as JSON: /api/errors/5a056b5b2b48f008.
Report an issue: GitHub.
Appendix: source
Thrown at gix-tix/src/edit/stash.rs:143
let head = repo
.head_id()
.context("stashing changes requires a born HEAD")?
.detach();
if head != id {
anyhow::bail!("changes can only be stashed at the current HEAD");
}
if repo
.index_or_empty()
.context("could not inspect the index before stashing")?
.entries()
.iter()
.any(|entry| entry.stage() != gix::index::entry::Stage::Unconflicted)
{
anyhow::bail!("cannot stash changes with unresolved index conflicts");
}
let name = reference(id)?;
if repo.try_find_reference(name.as_ref())?.is_some() {
anyhow::bail!("{} already has saved worktree state", id.to_hex_with_len(7));
}
drop(repo);
if !super::review::is_dirty(&workdir)? {
anyhow::bail!("there are no worktree or index changes to stash");
}
let saved = save(
repository_path,
bare,
&workdir,
name,
format!("tix {}", id.to_hex_with_len(7)),
"tix commit stash",
"commit state",
)?;
let mut notice = format!("stashed changes at {}", id.to_hex_with_len(7));
if let Some(warning) = saved.warning {
write!(notice, "; {warning}").expect("writing to a string cannot fail");
}View on GitHub (pinned to e73179060b)