fathyb/carbonyl · error
Unexpected mask value
Error message
Unexpected mask value
What it means
This panic comes from `FourBits::new`, which packs four booleans into a 4-bit value and maps it to a `FourBits` enum variant. Because four bools can only produce 0b0000..0b1111, the catch-all `_ => panic!("Unexpected mask value")` branch is logically unreachable — the Rust exhaustiveness checker can't prove that, so a defensive panic arm is required. It signals an internal invariant violation (e.g. corrupted match input), not user-callable invalid input.
Source
Thrown at src/utils/four_bits.rs:41
match (x as u8) << 3 | (y as u8) << 2 | (z as u8) << 1 | (w as u8) << 0 {
0b0000 => B0000,
0b0001 => B0001,
0b0010 => B0010,
0b0011 => B0011,
0b0100 => B0100,
0b0101 => B0101,
0b0110 => B0110,
0b0111 => B0111,
0b1000 => B1000,
0b1001 => B1001,
0b1010 => B1010,
0b1011 => B1011,
0b1100 => B1100,
0b1101 => B1101,
0b1110 => B1110,
0b1111 => B1111,
_ => panic!("Unexpected mask value"),
}
}
}
View on GitHub (pinned to ab80a276b1)
Solutions
- Verify the bit-packing expression shifts each bool into its own bit: (x as u8) << 3 | (y as u8) << 2 | (z as u8) << 1 | (w as u8).
- If inputs exceed four bits, widen the enum or split into multiple FourBits values instead of hitting the panic arm.
- Replace the panic with `unreachable!("Unexpected mask value")` or, better, make `new` return Result/self-documenting via TryFrom<u8> if arbitrary u8 input must be accepted.
- If the panic fires at runtime, add a debug_assert!/log of the computed mask value to identify the corrupted input path.
Example fix
// before
_ => panic!("Unexpected mask value"),
// after
_ => unreachable!("mask is built from 4 bools, value must be 0..=15"), Defensive patterns
Strategy: validation
Validate before calling
fn mask_from(x: bool, y: bool, z: bool, w: bool) -> u8 {
let m = (x as u8) << 3 | (y as u8) << 2 | (z as u8) << 1 | w as u8;
debug_assert!(m <= 0b1111, "mask {m} exceeds 4 bits");
m
} Type guard
fn is_four_bit(v: u8) -> bool { v <= 0b1111 } Try / catch
// panics cannot be caught in Rust; instead use catch_unwind if interfacing with FFI
let result = std::panic::catch_unwind(|| FourBits::new(x, y, z, w));
match result {
Ok(bits) => /* use bits */,
Err(_) => /* handle panic: log and fall back */,
} Prevention
- Keep `new` taking exactly four bools; do not pass raw u8 values into the bit-packing path.
- After changing shift/offset logic, add a test looping over all 16 bool combinations to prove the panic arm is unreachable.
- Prefer `unreachable!()` over `panic!()` for logically impossible arms so intent is clear.
- Consider `TryFrom<u8>` for the enum so invalid inputs become Result errors instead of panics.
When it happens
Trigger: Only reachable if the bit-packing expression in `FourBits::new` (src/utils/four_bits.rs:24) is modified to produce values outside 0b0000..0b1111 (e.g. shifting by wrong amounts, adding a fifth input, or using non-boolean-cast arithmetic). Calling `FourBits::new(x, y, z, w)` with any combination of four bools can never trigger it in the current code.
Common situations: Developers hit this after editing `new` (changed shift offsets, swapped `|` for `|=` on a wider type, extra inputs beyond 4 bits), or when refactoring the enum/mask types so the match receives a wider `u8`. It can also appear in coverage reports as an uncovered branch.
AI-assisted analysis of fathyb/carbonyl@ab80a276b1 (2026-09-02).
Data as JSON: /api/errors/d6e4d9b833b91bfd.
Report an issue: GitHub.