gleam-lang/gleam · error

trailing_zeros to return a value for non-zero numbers

Error message

trailing_zeros to return a value for non-zero numbers

What it means

When computing the required bit width for a negative integer pattern (adding sign bits), the code calls `trailing_zeros().expect(...)` which panics if the BigInt is zero — `trailing_zeros` returns None only for zero, but the comment says it is expected to be non-zero here. A zero value reaching this branch means the earlier zero/sign classification was wrong.

Solutions

  1. Fix the sign classification so zero is never classified as `Sign::Minus` (check `value == 0` before the match)
  2. Return the appropriate bit width directly for zero values before entering the negative branch
  3. Use `trailing_zeros().unwrap_or(bits_unsigned - 1)` style fallback only if zero can legitimately arrive
  4. Report a compiler bug with the literal that triggers it

Example fix

// before
let trailing_zeros = value.trailing_zeros().expect("trailing_zeros to return a value for non-zero numbers");
// after
let Some(trailing_zeros) = value.trailing_zeros() else {
    return 1; // value is zero despite negative sign classification
};
Defensive patterns

Strategy: type-guard

Validate before calling

if value.sign() == Sign::NoSign {
    return 1; // zero
}

Type guard

let Some(trailing_zeros) = value.trailing_zeros() else { return fallback_width(value); };

Prevention

When it happens

Trigger: The exhaustiveness integer-range analysis classifies a value as `Sign::Minus` (negative) but the value is actually zero, so `trailing_zeros()` returns None and the expect panics.

Common situations: Seen when adding large/edge-case integer literals to bit-array or case pattern checks in Gleam; typically caused by a sign-detection bug (e.g. comparing magnitudes incorrectly) or a custom BigInt literal that round-trips to zero.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of gleam-lang/gleam@49f8762da5 (2026-09-14). Data as JSON: /api/errors/51e3ef38b478204e. Report an issue: GitHub.

Appendix: source

Thrown at compiler-core/src/exhaustiveness.rs:4243

        return false;
    }

    let required_bits = match (value.sign(), signed) {
        // Zero always needs one bit.
        (Sign::NoSign, _) => 1,

        // `BigInt::bits` does not consider the sign!
        (Sign::Plus, false) => value.bits(),
        // Therefore we need to add the sign bit here: `10` -> `010`
        (Sign::Plus, true) => value.bits() + 1,

        // A negative number must be signed
        (Sign::Minus, false) => return false,
        (Sign::Minus, true) => {
            let bits_unsigned = value.bits();
            let trailing_zeros = value
                .trailing_zeros()
                .expect("trailing_zeros to return a value for non-zero numbers");
            let is_power_of_2 = trailing_zeros == bits_unsigned - 1;

            // Negative powers of two don't need an extra sign bit. E.g. `-2 == 0b10`
            if is_power_of_2 {
                bits_unsigned
            } else {
                bits_unsigned + 1
            }
        }
    };

    match required_bits.to_u32() {
        Some(required_bits) => bits >= required_bits,
        None => false,
    }
}

#[cfg(test)]

View on GitHub (pinned to 49f8762da5)