clockworklabs/SpacetimeDB · error

length didn't fit in `u32`

Error message

length didn't fit in `u32`

What it means

SlimStr packs its length into a u32, so it cannot represent strings longer than u32::MAX bytes (about 4 GiB). `from_str` is a const fn that enforces this with a panic instead of returning an error (the doc comment on the function says exactly this). Hitting it means a string at or beyond the 4 GiB structural limit was passed into the slim-slice representation; `from_string` delegates to `from_str` and panics the same way, while the fallible path is `SlimStr::try_from(&str)`, which uses the ensure_len_fits! check and returns Err instead.

Source

Thrown at crates/data-structures/src/slim_slice.rs:1369

}
impl<'a> TryFrom<&'a str> for SlimStr<'a> {
    type Error = LenTooLong<&'a str>;

    #[inline]
    fn try_from(s: &'a str) -> Result<Self, Self::Error> {
        ensure_len_fits!(s);
        // SAFETY: ^-- satisfies `len <= u32::MAX`.
        Ok(unsafe { Self::from_str_unchecked(s) })
    }
}

/// Converts `&str` into the slim limited version.
///
/// Panics when `str.len() > u32::MAX`.
#[inline]
pub const fn from_str(s: &str) -> SlimStr<'_> {
    if s.len() > u32::MAX as usize {
        panic!("length didn't fit in `u32`");
    }

    // SAFETY: ^-- satisfies `len <= u32::MAX`.
    unsafe { SlimStr::from_str_unchecked(s) }
}

/// Converts `&str` into the owned slim limited version.
///
/// Panics when `str.len() > u32::MAX`.
#[inline]
pub fn from_string(s: &str) -> SlimStrBox {
    from_str(s).into()
}

// =============================================================================
// Mutable string slice reference
// =============================================================================

View on GitHub (pinned to 6dee26c6ef)

Solutions

  1. Use the fallible conversion `SlimStr::try_from(s)` and handle the Err, instead of the panicking `from_str`.
  2. Check `s.len() <= u32::MAX as usize` before converting and reject or chunk the input.
  3. Move payloads that can grow unboundedly into bytes/blob columns instead of strings.
  4. If the value legitimately exceeds 4 GiB, split it across rows; the limit is structural to SlimStr.

Example fix

// before: panics when the string exceeds u32::MAX bytes
let slim = SlimStr::from_str(huge);

// after: fallible TryFrom<&str> returns Err instead (uses ensure_len_fits!)
let slim = SlimStr::try_from(huge)
    .map_err(|_| format!("string of {} bytes exceeds SlimStr u32 length limit", huge.len()))?;
Defensive patterns

Strategy: validation

Validate before calling

// prefer the fallible TryFrom<&str> (returns Err via ensure_len_fits!) over the panicking from_str
let slim = SlimStr::try_from(s)
    .map_err(|_| format!("string of {} bytes exceeds SlimStr u32 length limit", s.len()))?;

// or pre-check explicitly before any SlimStr conversion
if s.len() > u32::MAX as usize {
    return Err(format!("string of {} bytes exceeds SlimStr u32 length limit", s.len()));
}

Type guard

fn fits_slim_str(s: &str) -> bool { s.len() <= u32::MAX as usize }

Prevention

When it happens

Trigger: Calling SlimStr::from_str / SlimStr::from_string / From<&str> for SlimStr with s.len() > u32::MAX as usize; the const fn panics before any allocation happens.

Common situations: Loading oversized base64 blobs or whole files into string fields; property/fuzz tests generating huge strings; a serialization bug passing an entire buffer where a small key was expected.

Related errors


AI-assisted analysis of clockworklabs/SpacetimeDB@6dee26c6ef (2026-08-20). Data as JSON: /api/errors/5be5d00571997ce2. Report an issue: GitHub.