clockworklabs/SpacetimeDB · error

Invalid environment read response

Error message

Invalid environment read response

What it means

Thrown by `render` when the accumulated response body of an environment read cannot be parsed as JSON into `Vec<spacetimedb_client_api_messages::http::SqlStmtResult<Vec<String>>>`. The CLI expects the HTTP SQL endpoint's standard statement-result shape; anything else is rejected before rendering.

Solutions

  1. Check that CLI and server versions match (`spacetime version`); upgrade or downgrade to align them.
  2. Inspect the raw response (e.g. with `curl`) to see what the server actually returned.
  3. Confirm you are calling the /v1/database/sql endpoint of a SpacetimeDB server.
  4. Retry in case the response was truncated by a network fault.

Example fix

// server returned HTML due to wrong URL
// before
--server https://example.com        # serves HTML
// after
--server https://spacetimedb.example.com   # actual SpacetimeDB node
Defensive patterns

Strategy: validation

Validate before calling

// before parsing, sanity-check the body looks like JSON array output
if !body.trim_start().starts_with('[') {
    return Err("server did not return SQL statement results");
}

Type guard

fn looks_like_stmt_results(body: &[u8]) -> bool {
    serde_json::from_slice::<serde_json::Value>(body)
        .map(|v| v.is_array())
        .unwrap_or(false)
}

Prevention

When it happens

Trigger: `serde_json::from_slice(body)` fails — the server returned non-JSON (HTML error page, empty body, truncated stream) or JSON in an unexpected shape (object instead of array, different field types).

Common situations: CLI version mismatched with server version so the SQL response schema differs; a proxy returning an HTML error page; hitting the wrong URL path.

Understand the failure class

Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.

Related errors


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

Appendix: source

Thrown at crates/cli/src/subcommands/env.rs:122

    );
    let mut body = Vec::new();
    let limit = MAX_ENV_VARS * (MAX_ENV_KEY_BYTES + MAX_ENV_VALUE_BYTES) * 6 + 64 * 1024;
    let mut stream = response.bytes_stream();
    while let Some(chunk) = stream.next().await {
        let chunk = chunk?;
        ensure!(
            body.len().saturating_add(chunk.len()) <= limit,
            "Environment read response exceeds limit"
        );
        body.extend_from_slice(&chunk);
    }
    render(&body, &query)
}

fn render(body: &[u8], query: &Query) -> anyhow::Result<String> {
    // Validate the requested projection before rendering any response values.
    let results: Vec<spacetimedb_client_api_messages::http::SqlStmtResult<Vec<String>>> =
        serde_json::from_slice(body).map_err(|_| anyhow::anyhow!("Invalid environment read response"))?;
    ensure!(results.len() == 1, "Invalid environment read result count");
    let result = &results[0];
    let expected: &[&str] = match query {
        Query::List => &["key", "value"],
        Query::Get(_) => &["value"],
    };
    ensure!(
        result.schema.elements.len() == expected.len()
            && result.schema.elements.iter().zip(expected).all(|(column, name)| {
                column.name.as_deref() == Some(*name) && column.algebraic_type == spacetimedb_lib::AlgebraicType::String
            }),
        "Invalid environment read projection"
    );
    ensure!(result.rows.len() <= MAX_ENV_VARS, "Environment key count exceeds limit");
    for row in &result.rows {
        ensure!(row.len() == expected.len(), "Invalid environment read row");
        if matches!(query, Query::List) {
            validate_key(&row[0]).context("Invalid environment key in response")?;

View on GitHub (pinned to eddf9f5014)