clockworklabs/SpacetimeDB · error

Module exceeds publish size limit

Error message

Module exceeds publish size limit

What it means

The CLI's schema extraction reads a module file from disk and enforces the same publish size limit (`MAX_MODULE_BYTES`) that servers enforce, reading at most limit+1 bytes to detect overflow. It throws when the module binary on disk is larger than the maximum allowed publish size. This gives early, local feedback before any server interaction.

Solutions

  1. Build the module in release mode and strip debug info (e.g. `wasm-snip`, `wasm-opt -Oz`, or `strip`) to shrink the wasm below the limit.
  2. Check the file size first (`ls -lh target/wasm32-unknown-unknown/release/*.wasm`) and confirm you are extracting from the intended artifact.
  3. Remove or externalize large embedded data (assets, static strings) from the module.
  4. If the module genuinely needs more space, check whether the deployment's `MAX_MODULE_BYTES` permits it — the CLI enforces the same constant, so the module must shrink.

Example fix

// before: building with debug info
wasm32-unknown-unknown/debug/my_module.wasm  (> MAX_MODULE_BYTES)
// after
cargo build --release --target wasm32-unknown-unknown
wasm-opt -Oz --strip-debug my_module.wasm -o my_module.wasm  # now <= MAX_MODULE_BYTES
Defensive patterns

Strategy: validation

Validate before calling

use spacetimedb_client_api_messages::publish::MAX_MODULE_BYTES;
let size = std::fs::metadata(path)?.len();
if size > MAX_MODULE_BYTES as u64 {
    return Err(anyhow!("module {} is {} bytes, limit is {}", path.display(), size, MAX_MODULE_BYTES));
}

Try / catch

match read_program(&path) {
    Ok(bytes) => proceed(bytes),
    Err(e) if e.to_string().contains("publish size limit") => shrink_module_and_retry(),
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling `read_program(path)` (via `SchemaExtract::from_path`) on a module `.wasm` whose file size exceeds `spacetimedb_client_api_messages::publish::MAX_MODULE_BYTES`.

Common situations: Building the module with debug symbols / unstripped wasm, accidentally bundling large assets into the wasm binary, or pointing the extractor at the wrong (larger) artifact file.

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@eddf9f5014 (2026-09-20). Data as JSON: /api/errors/79fef556f32ee6f0. Report an issue: GitHub.

Appendix: source

Thrown at crates/cli/src/schema_extract.rs:51

fn inspect_blocking(extractor: PathBuf, bytes: Vec<u8>, host_type: String) -> anyhow::Result<ModuleDef> {
    std::thread::spawn(move || {
        tokio::runtime::Builder::new_current_thread()
            .enable_all()
            .build()?
            .block_on(inspect_with(extractor, bytes, host_type, INSPECT_TIMEOUT))
    })
    .join()
    .map_err(|_| anyhow::anyhow!("Local module inspection thread failed"))?
}

pub(crate) fn read_program(path: &std::path::Path) -> anyhow::Result<Vec<u8>> {
    use std::io::Read;
    let mut bytes = Vec::new();
    std::fs::File::open(path)?
        .take(spacetimedb_client_api_messages::publish::MAX_MODULE_BYTES as u64 + 1)
        .read_to_end(&mut bytes)?;
    ensure!(
        bytes.len() <= spacetimedb_client_api_messages::publish::MAX_MODULE_BYTES,
        "Module exceeds publish size limit"
    );
    Ok(bytes)
}

const MAX_SCHEMA_BYTES: u64 = 16 * 1024 * 1024;
const INSPECT_TIMEOUT: Duration = Duration::from_secs(60);

/// Inspect exactly the artifact bytes that will be uploaded. The private copy
/// prevents path replacement between inspection and upload, including --bin-path.
/// This invokes only local extraction, never a server or a saved CLI context.
pub(crate) async fn inspect(program: &[u8], host_type: &str) -> anyhow::Result<ModuleDef> {
    let extractor = extractor_path()?;
    inspect_with(extractor, program.to_vec(), host_type.to_owned(), INSPECT_TIMEOUT).await
}

pub(crate) async fn inspect_with(

View on GitHub (pinned to eddf9f5014)