clockworklabs/SpacetimeDB · error

Local module inspection thread failed

Error message

Local module inspection thread failed

What it means

inspect_blocking runs the module inspector on a spawned OS thread and uses thread::join().map_err(|_| ...). The error fires when the inspection thread itself panicked (JoinError), meaning the local inspection machinery crashed before producing a result — not that the module failed inspection.

Solutions

  1. Re-run the command; transient thread/runtime failures may not recur.
  2. Inspect server logs / RUST_BACKTRACE to find the panic that killed the inspection thread.
  3. Check memory/thread limits of the environment (CI containers often restrict thread creation).
  4. If reproducible, file/debug the underlying panic in the inspector pipeline; this error masks its real cause.
Defensive patterns

Strategy: retry

Try / catch

// CLI: catch the anyhow error, log RUST_BACKTRACE, retry once

Prevention

When it happens

Trigger: Calling from_path (synchronous schema extraction) when the inner std::thread::spawn closure panics — e.g. the tokio current-thread runtime fails to build, or inspect_with panics on the worker thread.

Common situations: Environments where tokio runtime construction fails (resource limits), or a bug/panic inside the inspection pipeline; also reproducible in tests that force the inspection thread to panic.

Related errors


AI-assisted analysis of clockworklabs/SpacetimeDB@eddf9f5014 (2026-09-20). Data as JSON: /api/errors/6b7a00edd9a54627. Report an issue: GitHub.

Appendix: source

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

pub(crate) fn from_path(path: &Path) -> anyhow::Result<ModuleDef> {
    let bytes = read_program(path)?;
    let host_type = match path.extension().and_then(|ext| ext.to_str()) {
        Some("wasm") => "Wasm",
        Some("js") => "Js",
        _ => anyhow::bail!("Cannot determine module type from file extension"),
    };
    inspect_blocking(extractor_path()?, bytes, host_type.into())
}

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);

View on GitHub (pinned to eddf9f5014)