clockworklabs/SpacetimeDB · error

Local module schema inspection timed out

Error message

Local module schema inspection timed out

What it means

inspect_observed wraps the child process's stdout read + wait in tokio::time::timeout(deadline, ...). When the deadline elapses before the inspector finishes, the arm maps the elapsed error to this anyhow error, then kills and reaps the child.

Solutions

  1. Retry; transient slowness may pass on a second attempt.
  2. Free up CPU/disk resources or run on a faster machine to fit within the fixed timeout.
  3. Reduce module size/complexity if it is unusually large.
  4. Update SpacetimeDB — newer versions may adjust the inspector timeout.
Defensive patterns

Strategy: retry

Try / catch

// CLI: on timeout error, inform user the inspector exceeded its deadline and suggest retry on a faster host

Prevention

When it happens

Trigger: The local module inspector process (extractor) does not write its schema and exit within INSPECT_TIMEOUT — e.g. a huge or pathological module, a hung extractor, or a very slow disk/CPU.

Common situations: Extracting schema from a large WASM module on a resource-starved CI runner; a stuck or buggy extractor binary; filesystem latency reading the module bytes.

Understand the failure class

Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.

Related errors


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

Appendix: source

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

            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"))?;
            Ok(schema)
        }

View on GitHub (pinned to eddf9f5014)