clockworklabs/SpacetimeDB · warning
Module inspection cancelled
Error message
Module inspection cancelled
What it means
Inside inspect_observed, a biased tokio::select! races the inspection child process against a cancellation channel. If the result sender (send) is dropped/closed — i.e. the caller gave up — the future resolves early with 'Module inspection cancelled' and the child is killed afterwards.
Solutions
- Retry the schema extraction and let it finish without cancelling.
- Investigate what dropped/closed the channel upstream (outer timeout, dropped future, closed connection).
- If cancellation is expected, treat this error as benign cleanup of the inspector child process.
- Increase any upstream deadline so inspection is not aborted prematurely.
Defensive patterns
Strategy: try-catch
Try / catch
match result { Err(e) if e.to_string().contains("cancelled") => { /* benign: caller dropped request */ }, other => other? } Prevention
- Don't abort extraction futures mid-flight unnecessarily
- Set realistic upstream deadlines
- Keep connections open until extraction completes
When it happens
Trigger: The owner of the inspection request drops the oneshot sender (e.g. the outer future is aborted, caller times out upstream, or request context is cancelled) while the inspector child process is still running.
Common situations: CLI requests cancelled by the user (Ctrl-C), HTTP connections closed mid-extraction, or an outer timeout firing and dropping the inspect future.
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
- fsync failed
- Local module schema inspection timed out
- log worker panicked
- a row was a sequence trigger but there was no generated…
- AddColumns: table ` ` not found in new module def
AI-assisted analysis of clockworklabs/SpacetimeDB@eddf9f5014 (2026-09-20).
Data as JSON: /api/errors/2e9bbe4b0fbdb23e.
Report an issue: GitHub.
Appendix: source
Thrown at crates/cli/src/schema_extract.rs:148
.arg(&module)
.arg("--host-type")
.arg(host_type.to_ascii_lowercase())
.stdin(Stdio::null())
.stdout(Stdio::piped())
.stderr(Stdio::null())
.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);
}View on GitHub (pinned to eddf9f5014)