gleam-lang/gleam · error
bytes must not be empty
Error message
bytes must not be empty
What it means
Inside the bit-width conversion for bit-array pattern/value matching, the code left-shifts the last byte of a byte vector to drop excess bits when the bit size isn't a multiple of 8. `bytes.last_mut().expect("bytes must not be empty")` panics if the byte vector is empty, i.e. a zero-byte BitVec was passed in. The invariant is that a bit array with a non-zero size in bits has at least one byte.
Solutions
- Ensure the bytes conversion produces at least one byte for any non-zero bit size before calling this code
- Short-circuit: if `bytes.is_empty()`, return `BitVec::new()` (or `BitVec::from_vec(bytes)`) instead of shifting
- Validate that segment `size > 0` and that `size`/8 == bytes.len() (or len+1) upstream
- If reproducible with valid Gleam source, file a compiler bug with the bit-array expression
Example fix
// before
let last_byte = bytes.last_mut().expect("bytes must not be empty");
*last_byte <<= 8 - remainder;
// after
if bytes.is_empty() {
return BitVec::new();
}
*bytes.last_mut().unwrap() <<= 8 - remainder; Defensive patterns
Strategy: validation
Validate before calling
if size == 0 || bytes.is_empty() {
return BitVec::new();
} Type guard
fn convertible(bytes: &[u8], size: usize) -> bool { !bytes.is_empty() && size > 0 && size <= bytes.len() * 8 } Prevention
- Always produce at least one byte from integer-to-bytes conversion for non-zero sizes
- Check segment size invariants before bit-level truncation
- Test bit-array patterns with size 0, 1..8, and multiples of 8
When it happens
Trigger: Calling the bit-array size/truncation helper with `bytes` empty while `remainder != 0` — e.g. size in bits > 0 but the byte conversion produced no bytes, or a zero-sized bit array segment whose remainder computation is inconsistent.
Common situations: Hit during Gleam compiler work on bit-array pattern matching: passing an empty `Vec<u8>` from an integer-to-bytes conversion for a zero value with a small segment size, or a bug in segment size validation.
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
- aliased non constant value
- case with no subjects
- Custom type constructor exist for type
- Custom type constructor must have custom type kind
- Should be a named type
AI-assisted analysis of gleam-lang/gleam@49f8762da5 (2026-09-14).
Data as JSON: /api/errors/087d60498e2d69b3.
Report an issue: GitHub.
Appendix: source
Thrown at compiler-core/src/exhaustiveness.rs:4061
}
// If the number needs fewer bits than the read size, we pad it.
// <3:9> yields the bytes [0b0000_0011]. We add one digit and get 0_0000_0011
(Endianness::Big, Ordering::Less) => {
let mut bits = BitVec::repeat(pad_digit, size - bytes_size);
bits.extend_from_raw_slice(&bytes);
bits
}
(Endianness::Little, Ordering::Greater) => {
// If the difference is greater than a byte, we returned an Error earlier
let remainder = size % 8;
if remainder == 0 {
BitVec::from_vec(bytes)
} else {
// If the size is not a multiple of 8, we need to truncate the most significant bits.
// As they are in the last byte, we leftshift by the appropriate amount and
// truncate the final bits after conversion
let last_byte = bytes.last_mut().expect("bytes must not be empty");
*last_byte <<= 8 - remainder;
let mut bits = BitVec::from_vec(bytes);
bits.truncate(size);
bits
}
}
(Endianness::Little, Ordering::Less) => {
let mut bits = BitVec::from_vec(bytes);
let padding: BitVec<u8, Msb0> = BitVec::repeat(pad_digit, size - bytes_size);
bits.extend_from_bitslice(padding.as_bitslice());
bits
}
};
Ok(bits)
}
fn int_to_bytes(value: &BigInt, endianness: Endianness, signed: bool) -> Vec<u8> {View on GitHub (pinned to 49f8762da5)