zed-industries/zed · error

invalid git oid hex length: expected 1..={SHA1_HEX_LENGTH} f

Error message

invalid git oid hex length: expected 1..={SHA1_HEX_LENGTH} for SHA-1 or {SHA256_HEX_LENGTH} for SHA-256, got {len}

What it means

Oid::from_str classifies the hex string purely by length: 1..=40 hex chars are treated as an abbreviated-or-full SHA-1 oid, exactly 64 as SHA-256, and anything else bails with the observed length. There is deliberately no middle ground — 41-63 chars, 0 chars (empty string), or >64 are all rejected before any hex-digit decoding happens.

Source

Thrown at crates/git/src/git.rs:290

}

impl TryFrom<&str> for Oid {
    type Error = anyhow::Error;

    fn try_from(value: &str) -> std::result::Result<Self, Self::Error> {
        Oid::from_str(value)
    }
}

impl FromStr for Oid {
    type Err = anyhow::Error;

    fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
        let format = match s.len() {
            1..=SHA1_HEX_LENGTH => OidFormat::Sha1,
            SHA256_HEX_LENGTH => OidFormat::Sha256,
            len => {
                anyhow::bail!(
                    "invalid git oid hex length: expected 1..={SHA1_HEX_LENGTH} for SHA-1 or {SHA256_HEX_LENGTH} for SHA-256, got {len}"
                );
            }
        };

        let mut bytes = [0u8; SHA256_BYTE_LENGTH];
        for (index, byte) in s.bytes().enumerate() {
            let digit = decode_hex_digit(byte)
                .ok_or_else(|| anyhow::anyhow!("invalid hex digit at byte {index} for git oid"))?;
            if index % 2 == 0 {
                bytes[index / 2] = digit << 4;
            } else {
                bytes[index / 2] |= digit;
            }
        }

        Ok(Self { bytes, format })
    }

View on GitHub (pinned to f4178619ac)

Solutions

  1. Trim whitespace/newlines from the string before parsing
  2. Check the length: use a full 40-char SHA-1, an abbreviation of 1–40 chars, or a full 64-char SHA-256
  3. Fix the upstream splitting/format string (e.g. %x00 delimiters) so oids arrive clean

Example fix

// before
let oid: Oid = line_with_trailing_newline.parse()?; // len 41 -> invalid git oid hex length

// after
let oid = Oid::from_str(line.trim())?;
Defensive patterns

Strategy: type-guard

Validate before calling

let s = s.trim();
if !(1..=40).contains(&s.len()) && s.len() != 64 {
    return Err(format!("oid string has invalid length {}", s.len()));
}

Type guard

fn is_valid_oid_hex(s: &str) -> bool {
    let len = s.len();
    ((1..=40).contains(&len) || len == 64) && s.bytes().all(|b| b.is_ascii_hexdigit())
}

Try / catch

let oid = match Oid::from_str(raw) {
    Ok(oid) => oid,
    Err(e) if e.to_string().contains("hex length") => Oid::from_str(raw.trim())?,
    Err(e) => return Err(e),
};

Prevention

When it happens

Trigger: Parsing an oid string with 41–63 hex characters (e.g. a SHA-1 with appended characters or a truncated SHA-256), an empty string, a 65+ char string, or text with whitespace/newlines inflating the length.

Common situations: Splitting git output on the wrong delimiter leaving trailing characters, concatenated oids not re-split, user-pasted revs with spaces or newlines, or copying 64+ char strings from non-git tools.

Related errors


AI-assisted analysis of zed-industries/zed@f4178619ac (2026-08-20). Data as JSON: /api/errors/9f9c2c8390bee638. Report an issue: GitHub.