clockworklabs/SpacetimeDB · error · anyhow::Error

{e}

Error message

{e}

What it means

Surfaced by `spacetime call` when the reducer-invocation HTTP response has an error status AND the attempt to read the response body for a better message itself fails. The CLI can only re-raise the underlying transport error (status/URL, no body context), so what you see means: the call failed at HTTP level and even the error body could not be read.

Source

Thrown at crates/cli/src/subcommands/call.rs:143

                match argument.as_bytes() {
                    [b'0', b'x', ..] => format!("[\"{argument}\"]"),
                    [b'c', b'2', b'0', b'0', ..] => format!("[\"0x{argument}\"]"),
                    _ => argument.to_string(),
                }
            }
            AlgebraicType::String if !argument.starts_with('\"') || !argument.ends_with('\"') => {
                format!("\"{argument}\"")
            }
            _ => argument.to_string(),
        });

    let arg_json = format!("[{}]", arguments.format(", "));
    let res = api.call(reducer_procedure_name, arg_json).await?;

    if let Err(e) = res.error_for_status_ref() {
        let Ok(response_text) = res.text().await else {
            // Cannot give a better error than this if we don't know what the problem is.
            bail!(e);
        };

        let error = Err(e).context(format!("Response text: {response_text}"));

        let error_msg =
            if response_text.starts_with("no such reducer") || response_text.starts_with("no such procedure") {
                no_such_reducer_or_procedure(&database_identity, database, reducer_procedure_name, &module_def)
            } else if response_text.starts_with("invalid arguments") {
                invalid_arguments(
                    &database_identity,
                    database,
                    &response_text,
                    owning_def.typespace(),
                    reducer_procedure_name,
                    call_def,
                )
            } else {
                return error;

View on GitHub (pinned to 6dee26c6ef)

Solutions

  1. Retry the call — transient transport failure is the usual cause
  2. Check server health and logs: `spacetime logs`, server process status, or a restart
  3. Verify the database and reducer exist (`spacetime describe <db>`, `spacetime describe <db> reducer <name>`) to rule out 404-style causes hidden by the missing body
  4. If behind a proxy, bypass it or raise body-size/timeout limits

Example fix

# before
spacetime call my-db add Alice
# Error: HTTP status client error ... (no response text)

# after
# 1) confirm the target exists
spacetime describe my-db reducer add
# 2) retry; if it persists, inspect the server
spacetime logs --server local
Defensive patterns

Strategy: retry

Validate before calling

// fail fast with a readable error before calling
let db = api.database(&name).await.map_err(|e| anyhow::anyhow!("db lookup failed: {e}"))?;

Try / catch

match res.error_for_status_ref() {
    Ok(_) => {}
    Err(e) if e.is_connect() || e.is_timeout() || e.is_body() => { /* backoff and retry */ }
    Err(e) => return Err(e).context("reducer call failed"),
}

Prevention

When it happens

Trigger: POST to the call endpoint returns non-2xx and `res.text().await` errors — connection reset mid-body, proxy truncation, TLS interruption, or the server crashing while streaming the error response.

Common situations: Flaky networks, corporate proxies, an overloaded or restarting server, or a database publish failure that kills the connection before the error body is flushed.

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


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