GitoxideLabs/gitoxide · error · anyhow::Error

{err}

Error message

{err}

What it means

In `merge commit`, tree objects produced by the merge are written with `repo.write(tree)`, and any error from the object write is mapped into a bare `anyhow!("{err}")`. The message is simply the underlying error string — typically an object-database write failure (disk full, permission denied, corrupt odb) — re-raised without additional context.

Solutions

  1. Inspect the inner error text for the real cause and fix it (permissions, disk space)
  2. Verify `.git/objects` is writable: `ls -ld .git/objects` and `chmod -R u+w .git/objects` if needed
  3. Free disk space or repair the object database (`git fsck`) before retrying the merge

Example fix

// before
$ gix repo merge main --commit
error: permission denied
// after
$ chmod -R u+w .git/objects
$ gix repo merge main --commit
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-flight: object db must be writable
let objects_dir = repo.path().join("objects");
let probe = objects_dir.join(".write_probe");
std::fs::write(&probe, b"").map_err(|e| format!("object db not writable: {e}"))?;
std::fs::remove_file(&probe)?;

Try / catch

match merge_commit(...) {
    Err(e) => {
        // inner odb error is flattened into the message; check permissions/space
        eprintln!("tree write failed: {e}; check .git/objects perms and disk space");
        std::process::exit(1);
    }
    Ok(v) => v,
}

Prevention

When it happens

Trigger: Calling `gix repo merge <tree-ish> --commit` (via `commit`) when writing a tree object to the object database fails, e.g. `.git/objects` is read-only or the disk is full.

Common situations: Read-only checkouts on CI, insufficient filesystem permissions, full disks, or corrupted loose-object directories during merge --commit.

Related errors


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

Appendix: source

Thrown at gitoxide-core/src/repository/merge/commit.rs:69

            .map_or(theirs_id_str.as_str().into(), |n| n.as_bstr())
            .into(),
    };
    let res = repo
        .merge_commits(ours_id, theirs_id, labels, options.into())?
        .tree_merge;
    let has_conflicts = res.conflicts.is_empty();
    let has_unresolved_conflicts = res.has_unresolved_conflicts(TreatAsUnresolved::default());
    {
        let _span = gix::trace::detail!("Writing merged tree");
        let mut written = 0;
        let tree_id = res
            .tree
            .detach()
            .write(|tree| {
                written += 1;
                repo.write(tree)
            })
            .map_err(|err| anyhow!("{err}"))?;
        writeln!(out, "{tree_id} (wrote {written} trees)")?;
    }

    if debug {
        writeln!(err, "{:#?}", res.conflicts)?;
    }
    if !has_conflicts {
        writeln!(err, "{} possibly resolved conflicts", res.conflicts.len())?;
    }
    if has_unresolved_conflicts {
        bail!("Tree conflicted")
    }
    Ok(())
}

fn refname_and_commit(
    repo: &gix::Repository,
    revspec: BString,

View on GitHub (pinned to e73179060b)