clockworklabs/SpacetimeDB · error

Local module schema inspection failed

Error message

Local module schema inspection failed

What it means

After reading the inspector's stdout, the CLI reaps the module inspector subprocess and requires a successful exit status. A non-zero status means the local inspector (the module run for schema extraction) crashed, panicked, or otherwise failed, so its schema cannot be trusted and inspection fails.

Solutions

  1. Run the module locally and fix the panic/trap reported in the inspector's stderr (module init or reducer panics are the usual cause).
  2. Rebuild the module matching the toolchain/ABI the inspector expects (align `spacetimedb` crate and CLI versions).
  3. Check inspector stderr and exit code for missing binaries or runtime issues; install missing dependencies.
  4. Verify with `spacetime publish` to a local server to see whether the module initializes correctly outside the extraction path.

Example fix

// before: module init panics during inspection
#[spacetimedb::reducer(init)]
fn init(ctx: &ReducerContext) { panic!("oops"); }
// after
#[spacetimedb::reducer(init)]
fn init(ctx: &ReducerContext) {
    ctx.db.users.insert(User { id: 0 });
}
Defensive patterns

Strategy: try-catch

Validate before calling

// run the module once locally and check it initializes cleanly
let status = std::process::Command::new(&inspector_path).arg(&module).status()?;
if !status.success() { return Err(anyhow!("module inspector would fail; fix module init first")); }

Try / catch

match inspect_observed(...) {
    Ok(observation) => use_schema(observation),
    Err(e) if e.to_string().contains("inspection failed") => {
        log::error!("module inspector exited non-zero: {e}; check module init/panic");
        fix_module_and_retry();
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: `inspect_observed` calls `child.wait()` and the inspector process exits non-zero — e.g. the wasm module panics during initialization, the inspector binary is incompatible with the module, or the module traps while emitting its schema.

Common situations: A module whose `__preupload__`/init code panics; running the inspector against a module built for a different ABI/toolchain version; missing runtime dependencies for the inspector subprocess.

Related errors


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

Appendix: source

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

                .kill_on_drop(true);
            configure_inspector_environment(&mut command);
            let mut child = command.spawn().context("Cannot start local module schema inspection")?;
            observation.started(child.id());
            let mut output = Vec::new();
            let mut stdout = child
                .stdout
                .take()
                .context("Module inspection stdout unavailable")?
                .take(MAX_SCHEMA_BYTES + 1);
            let result = tokio::select! {
                biased;
                _ = send.closed() => Err(anyhow::anyhow!("Module inspection cancelled")),
                result = tokio::time::timeout(deadline, async {
                    stdout.read_to_end(&mut output).await.context("Cannot read local module schema")?;
                    ensure!(output.len() as u64 <= MAX_SCHEMA_BYTES, "Local module schema exceeds output limit");
                    let status = child.wait().await.context("Cannot reap local module inspector")?;
                    observation.reaped(status);
                    ensure!(status.success(), "Local module schema inspection failed");
                    Ok(())
                }) => result.unwrap_or_else(|_| Err(anyhow::anyhow!("Local module schema inspection timed out"))),
            };
            if result.is_err() {
                // Queue termination, then retain ownership through positive reaping.
                let _ = child.start_kill();
                let status = child
                    .wait()
                    .await
                    .context("Cannot reap failed local module inspector")?;
                observation.reaped(status);
            }
            result?;
            // Neither parser nor validation diagnostics may echo schema literals.
            let SerdeWrapper::<RawModuleDef>(raw) = serde_json::from_slice(&output)
                .map_err(|_| anyhow::anyhow!("Local module inspector returned invalid schema data"))?;
            let schema =
                ModuleDef::try_from(raw).map_err(|_| anyhow::anyhow!("Local module schema validation failed"))?;

View on GitHub (pinned to eddf9f5014)