zed-industries/zed · error

unexpected number of shas

Error message

unexpected number of shas

What it means

While resolving MERGE_HEAD, the code feeds each rev to `git cat-file` and maps lines to Option<String> (None for "missing"), then requires shas.len() == revs.len(). In an octopus merge MERGE_HEAD lists multiple shas but the batched cat-file invocation only yields one, so the counts diverge and it bails — the inline comment documents this exact git behavior. It is a known upstream limitation, not a repository corruption signal.

Source

Thrown at crates/git/src/repository.rs:1746

                        .envs(env.iter())
                        .arg(path.as_unix_str())
                        .output()
                        .await?;

                    anyhow::ensure!(
                        output.status.success(),
                        "Failed to stage:\n{}",
                        String::from_utf8_lossy(&output.stderr)
                    );
                } else {
                    log::debug!("removing path {path:?} from the index");
                    let output = git
                        .build_command(&["update-index", "--force-remove", "--"])
                        .envs(env.iter())
                        .arg(path.as_unix_str())
                        .output()
                        .await?;
                    anyhow::ensure!(
                        output.status.success(),
                        "Failed to unstage:\n{}",
                        String::from_utf8_lossy(&output.stderr)
                    );
                }

                Ok(())
            })
            .boxed()
    }

    fn remote_urls(&self) -> BoxFuture<'_, HashMap<String, String>> {
        let git = self.git_binary();
        self.executor
            .spawn(async move {
                if let Ok(stdout) = git.run(&["remote", "-v"]).await {
                    parse_remote_urls(&stdout)
                } else {

View on GitHub (pinned to 5a9b9558db)

Solutions

  1. Finish or abort the octopus merge (git merge --abort) and redo it as sequential pairwise merges, then retry
  2. Pass each rev as a separate cat-file argument (or loop) so every MERGE_HEAD line gets a sha, if you control the code
  3. Track/patch the upstream issue so MERGE_HEAD is parsed line-wise instead of via batched cat-file
Defensive patterns

Strategy: try-catch

Validate before calling

// before resolving merge-head shas: count MERGE_HEAD lines
let merge_head = smol::fs::read_to_string(".git/MERGE_HEAD").await?;
if merge_head.lines().count() > 1 {
    // octopus merge: known cat-file limitation, handle before calling load_merge_head
}

Try / catch

match load_merge_head().await {
    Ok(shas) => Ok(shas),
    Err(e) if e.to_string().contains("unexpected number of shas") => {
        // octopus merge in progress: read .git/MERGE_HEAD line-wise as the source of truth
        parse_merge_head_file().await
    }
    Err(e) => Err(e),
}

Prevention

When it happens

Trigger: Loading merge-head shas while an octopus merge (merging 2+ branches at once, MERGE_HEAD with multiple lines) is in progress.

Common situations: Starting a commit-message flow during `git merge branch-a branch-b`, or scripts/extensions initiating multi-branch merges; anything that reads merge parents mid-octopus-merge hits it.

Related errors


AI-assisted analysis of zed-industries/zed@5a9b9558db (2026-08-20). Data as JSON: /api/errors/1b84c758712d990a. Report an issue: GitHub.