clockworklabs/SpacetimeDB · error · anyhow::Error

`create_bytes_source`: `Bytes` has length {}, which is great

Error message

`create_bytes_source`: `Bytes` has length {}, which is greater than `u32::MAX` {}

What it means

WasmInstanceEnv::create_bytes_source stores a host-side bytes::Bytes buffer for the wasm32 guest to consume via syscalls. The bytes_source_remaining_length syscall reports the length as a u32, so buffers larger than u32::MAX (about 4 GiB) cannot be represented; additionally the guest cannot hold such a buffer in WASM32 memory. The host therefore rejects oversized buffers up front instead of overflowing.

Source

Thrown at crates/core/src/host/wasmtime/wasm_instance_env.rs:262

            .expect("allocating next `BytesSink` overflowed `u32`");
        id
    }

    /// Binds `bytes` to the environment and assigns it an ID.
    ///
    /// If `bytes` is empty, `BytesSourceId::INVALID` is returned.
    fn create_bytes_source(&mut self, bytes: bytes::Bytes) -> RtResult<BytesSourceId> {
        // Pass an invalid source when the bytes were empty.
        // This allows the module to avoid allocating and make a system call in those cases.
        if bytes.is_empty() {
            Ok(BytesSourceId::INVALID)
        } else if bytes.len() > u32::MAX as usize {
            // There's no inherent reason we need to error here,
            // other than that it makes it impossible to report the length in `bytes_source_remaining_length`
            // and that all of our usage of `BytesSource`s as of writing (pgoldman 2025-09-26)
            // are to immediately slurp the whole thing into a buffer in guest memory,
            // which can't hold buffers this big because it's WASM32.
            Err(anyhow::anyhow!(
                "`create_bytes_source`: `Bytes` has length {}, which is greater than `u32::MAX` {}",
                bytes.len(),
                u32::MAX,
            ))
        } else {
            let id = self.alloc_bytes_source_id()?;
            self.bytes_sources.insert(id, BytesSource { bytes });
            Ok(id)
        }
    }

    pub fn create_extra_bytes_source(&mut self, bytes: bytes::Bytes) -> RtResult<BytesSourceId> {
        self.create_bytes_source(bytes)
    }

    fn free_bytes_source(&mut self, id: BytesSourceId) {
        if self.bytes_sources.remove(&id).is_none() {
            log::warn!("`free_bytes_source` on non-existent source {id:?}");

View on GitHub (pinned to 6dee26c6ef)

Solutions

  1. Enforce a maximum payload size at the API boundary and reject oversize inputs with a clear message before they reach the host bridge
  2. Split the payload into chunks below the limit and reassemble in the module or across multiple calls
  3. Store very large blobs out-of-band and pass a reference instead of raw bytes

Example fix

// before
let id = env.create_bytes_source(bytes)?; // bytes.len() > u32::MAX -> error

// after
const MAX_BYTES: usize = u32::MAX as usize;
if bytes.len() > MAX_BYTES {
    return Err(anyhow::anyhow!(
        "payload of {} bytes exceeds the 4 GiB wasm bridge limit; chunk the upload",
        bytes.len(),
    ));
}
let id = env.create_bytes_source(bytes)?;
Defensive patterns

Strategy: validation

Validate before calling

// Validate payload size before crossing the wasm bridge
const MAX_BYTES_SOURCE: usize = u32::MAX as usize;

fn check_bytes_source_size(len: usize) -> Result<(), anyhow::Error> {
    if len > MAX_BYTES_SOURCE {
        Err(anyhow::anyhow!("payload of {len} bytes exceeds the 4 GiB wasm bridge limit"))
    } else {
        Ok(())
    }
}

Type guard

fn fits_bytes_source(bytes: &bytes::Bytes) -> bool {
    !bytes.is_empty() && bytes.len() <= u32::MAX as usize
}

Try / catch

match env.create_bytes_source(bytes) {
    Err(e) if e.to_string().contains("greater than `u32::MAX`") => {
        // Reject or chunk the upload at the API boundary
    }
    other => other,
}

Prevention

When it happens

Trigger: Passing a reducer argument, message, or blob larger than 4 GiB minus 1 into a host call that creates a bytes source (e.g. via create_extra_bytes_source on the instance env).

Common situations: Bulk-loading very large binary payloads in a single call; unbounded user-supplied input sizes; tests with synthetic huge buffers.

Understand the failure class

Background: payload too large / request exceeds maximum size: why libraries cap bytes and how to fix oversize payloads — this error's family across 50 libraries.

Related errors


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