{"record":{"id":"1b84c758712d990a","repo":"zed-industries/zed","slug":"unexpected-number-of-shas","errorCode":null,"errorMessage":"unexpected number of shas","messagePattern":"unexpected number of shas","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/git/src/repository.rs","lineNumber":1746,"sourceCode":"                        .envs(env.iter())\n                        .arg(path.as_unix_str())\n                        .output()\n                        .await?;\n\n                    anyhow::ensure!(\n                        output.status.success(),\n                        \"Failed to stage:\\n{}\",\n                        String::from_utf8_lossy(&output.stderr)\n                    );\n                } else {\n                    log::debug!(\"removing path {path:?} from the index\");\n                    let output = git\n                        .build_command(&[\"update-index\", \"--force-remove\", \"--\"])\n                        .envs(env.iter())\n                        .arg(path.as_unix_str())\n                        .output()\n                        .await?;\n                    anyhow::ensure!(\n                        output.status.success(),\n                        \"Failed to unstage:\\n{}\",\n                        String::from_utf8_lossy(&output.stderr)\n                    );\n                }\n\n                Ok(())\n            })\n            .boxed()\n    }\n\n    fn remote_urls(&self) -> BoxFuture<'_, HashMap<String, String>> {\n        let git = self.git_binary();\n        self.executor\n            .spawn(async move {\n                if let Ok(stdout) = git.run(&[\"remote\", \"-v\"]).await {\n                    parse_remote_urls(&stdout)\n                } else {","sourceCodeStart":1728,"sourceCodeEnd":1764,"githubUrl":"https://github.com/zed-industries/zed/blob/5a9b9558db01a6b906cec2fb70a797affdc58cdd/crates/git/src/repository.rs#L1728-L1764","documentation":"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.","triggerScenarios":"Loading merge-head shas while an octopus merge (merging 2+ branches at once, MERGE_HEAD with multiple lines) is in progress.","commonSituations":"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.","solutions":["Finish or abort the octopus merge (git merge --abort) and redo it as sequential pairwise merges, then retry","Pass each rev as a separate cat-file argument (or loop) so every MERGE_HEAD line gets a sha, if you control the code","Track/patch the upstream issue so MERGE_HEAD is parsed line-wise instead of via batched cat-file"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// before resolving merge-head shas: count MERGE_HEAD lines\nlet merge_head = smol::fs::read_to_string(\".git/MERGE_HEAD\").await?;\nif merge_head.lines().count() > 1 {\n    // octopus merge: known cat-file limitation, handle before calling load_merge_head\n}","typeGuard":null,"tryCatchPattern":"match load_merge_head().await {\n    Ok(shas) => Ok(shas),\n    Err(e) if e.to_string().contains(\"unexpected number of shas\") => {\n        // octopus merge in progress: read .git/MERGE_HEAD line-wise as the source of truth\n        parse_merge_head_file().await\n    }\n    Err(e) => Err(e),\n}","preventionTips":["Prefer sequential pairwise merges over `git merge a b c` octopus merges","Parse MERGE_HEAD directly (one sha per line) when multi-parent merges must be supported"],"tags":["git","merge","octopus-merge","merge-head","cat-file"],"backgroundTag":"git-output-parse-error","analyzedSha":"5a9b9558db01a6b906cec2fb70a797affdc58cdd","analyzedAt":"2026-08-20T19:29:52.058Z","contentChangedAt":"2026-08-20T19:29:52.058Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}