zed-industries/zed · error
revision spec {revision:?} contains a newline and cannot be
Error message
revision spec {revision:?} contains a newline and cannot be passed to git cat-file --batch What it means
load_revisions() batches revision lookups by writing every spec to the stdin of one `git cat-file --batch` process. The batch protocol delimits requests by newline, so a revision spec that itself contains a newline would be split into extra requests and desynchronize the responses. The library therefore rejects the whole batch before spawning git when any revision contains a newline.
Source
Thrown at crates/git/src/repository.rs:1765
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 {
HashMap::default()
}
})
.boxed()
}
fn revparse_batch(&self, revs: Vec<String>) -> BoxFuture<'_, Result<Vec<Option<String>>>> {
let git = self.git_binary();
self.executor
.spawn(async move {
let mut process = git
.build_command(&["cat-file", "--batch-check=%(objectname)"])
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()?;
let stdin = process
.stdinView on GitHub (pinned to 5a9b9558db)
Solutions
- Trim and validate revision strings before passing them in: reject any spec containing a newline (and ideally enforce a strict revision charset such as A-Za-z0-9._/^~@:%-).
- Sanitize at the input boundary (trim user-pasted text) instead of at the git call site.
- Resolve each spec to a full SHA individually with `git rev-parse --verify <spec>` first, then batch the resolved SHAs, which are guaranteed newline-free.
- If the newline arrived via a ref you created, fix the script that created the malformed ref.
Example fix
// before
let contents = repo.load_revisions(vec![revision_from_user.clone()]).await?;
// after
let revision_from_user = revision_from_user.trim();
anyhow::ensure!(!revision_from_user.contains('\n'), "invalid revision spec: {revision_from_user:?}");
let contents = repo.load_revisions(vec![revision_from_user.to_owned()]).await?; Defensive patterns
Strategy: validation
Validate before calling
fn sanitize_revision(spec: &str) -> anyhow::Result<&str> {
let trimmed = spec.trim();
anyhow::ensure!(
!trimmed.is_empty() && !trimmed.contains('\n') && !trimmed.contains('\0'),
"revision spec contains control characters: {spec:?}"
);
Ok(trimmed)
}
let revisions = revisions
.iter()
.map(|r| sanitize_revision(r).map(str::to_owned))
.collect::<Result<Vec<_>>>()?;
let contents = repo.load_revisions(revisions).await?; Try / catch
match repo.load_revisions(revisions).await {
Err(e) if e.to_string().contains("cannot be passed to git cat-file") => {
// bad input: sanitize the specs instead of retrying
}
other => other?,
} Prevention
- Trim all user-supplied text at the input boundary before it can become a revision spec.
- Validate revision specs against a strict charset (no control characters) in one shared helper used by every call site.
- Pre-resolve specs to full SHAs with `git rev-parse --verify` before batching them into cat-file.
When it happens
Trigger: Calling a repository API that ends in load_revisions (batch-loading blob contents for multiple revisions, e.g. blame or project diff reading old file versions) where at least one revision string contains a newline. The offending spec is printed with Debug formatting ({revision:?}) so the message shows the embedded \n.
Common situations: Revision strings assembled from untrusted or loosely validated input: text pasted by a user (trailing newline never trimmed), refs parsed out of commit messages, or scripting bugs that embed newlines into ref names. Cheap sanitization is applied to URLs and paths but not to revision specs.
Related errors
- unexpected number of shas
- invalid cat-file header: {header_line}
- object not found: {}
- expected commit object, got {object_type}
- grammar directory '{}' already exists, but is not a git clon
AI-assisted analysis of zed-industries/zed@5a9b9558db (2026-08-20).
Data as JSON: /api/errors/ffdb08027da4d4ba.
Report an issue: GitHub.