gleam-lang/gleam · error

Failed to split 'b' slice

Error message

Failed to split 'b' slice

What it means

This `expect` guards `b.split_last()` inside the Levenshtein-style `did_you_mean` similarity helper in `compiler-core/src/error.rs`. The loop precondition `!b.is_empty() && !a.is_empty()` should guarantee both slices are non-empty, so `split_last` can only fail if the slices were mutated concurrently or the invariant is broken elsewhere — making this an internal defensive assertion, not an expected user-facing error.

Solutions

  1. File a compiler bug with the input that triggered suggestion generation if this panic is ever observed
  2. Upgrade Gleam to a version where the suggestion helper has been audited
  3. As a library change, replace `expect` with a `match` that returns `None` on empty slices so the helper degrades gracefully instead of panicking

Example fix

// before
let (b_first, b_rest) = b.split_last().expect("Failed to split 'b' slice");
// after
let Some((b_first, b_rest)) = b.split_last() else { return None; };
let Some((a_first, a_rest)) = a.split_last() else { return None; };
Defensive patterns

Strategy: fallback

Validate before calling

// Not user-triggerable; if embedding the crate, verify inputs to did_you_mean are non-empty:
assert!(!a.is_empty() && !b.is_empty(), "did_you_mean requires non-empty slices");

Try / catch

// no user-side catch exists for an ICE; isolate compiler runs:
let out = std::process::Command::new("gleam").arg("build").output();
if let Err(e) = out { eprintln!("compiler crashed: {e}"); }

Prevention

When it happens

Trigger: Panics only if `split_last` is called on an empty slice despite the while-loop guard, i.e. a logic bug upstream in how `a`/`b` are computed or sliced, or unsafe concurrent mutation of the slices between the emptiness check and the split.

Common situations: Effectively never hit by library users; it would appear as a compiler panic (ICE) while generating a 'did you mean' suggestion for a mistyped identifier, only in the presence of a compiler bug or data race.

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/ff19549bc5e0bfeb. Report an issue: GitHub.

Appendix: source

Thrown at compiler-core/src/error.rs:829

// https://github.com/rust-lang/rust/blob/03994e498df79aa1f97f7bbcfd52d57c8e865049/compiler/rustc_span/src/edit_distance.rs
pub fn edit_distance(a: &str, b: &str, limit: usize) -> Option<usize> {
    let mut a = &a.chars().collect::<Vec<_>>()[..];
    let mut b = &b.chars().collect::<Vec<_>>()[..];

    if a.len() < b.len() {
        std::mem::swap(&mut a, &mut b);
    }

    let min_dist = a.len() - b.len();
    // If we know the limit will be exceeded, we can return early.
    if min_dist > limit {
        return None;
    }

    // Strip common prefix.
    while !b.is_empty() && !a.is_empty() {
        let (b_first, b_rest) = b.split_last().expect("Failed to split 'b' slice");
        let (a_first, a_rest) = a.split_last().expect("Failed to split 'a' slice");

        if b_first == a_first {
            a = a_rest;
            b = b_rest;
        } else {
            break;
        }
    }

    // If either string is empty, the distance is the length of the other.
    // We know that `b` is the shorter string, so we don't need to check `a`.
    if b.is_empty() {
        return Some(min_dist);
    }

    let mut prev_prev = vec![usize::MAX; b.len() + 1];
    let mut prev = (0..=b.len()).collect::<Vec<_>>();

View on GitHub (pinned to 49f8762da5)