clockworklabs/SpacetimeDB · error

Invalid environment read projection

Error message

Invalid environment read projection

What it means

Thrown by `render` when the single SQL statement result's schema does not match the expected projection: for `Query::List` the columns must be exactly `key` and `value`, for `Query::Get` exactly `value`, all of `AlgebraicType::String`. This validates the server returned the exact requested columns before rendering values.

Solutions

  1. Upgrade or downgrade the CLI to match the server version.
  2. Verify the environment-read SQL used matches the current server's supported syntax.
  3. If behind a proxy, ensure it does not rewrite the SQL response schema.
  4. Report/inspect the raw JSON response to see the actual column names and types.
Defensive patterns

Strategy: validation

Validate before calling

// confirm expected columns before use
assert_eq!(result.schema.elements.len(), expected.len());

Type guard

fn has_expected_schema(r: &SqlStmtResult<Vec<String>>, expected: &[&str]) -> bool {
    r.schema.elements.len() == expected.len()
        && r.schema.elements.iter().zip(expected)
            .all(|(c, n)| c.name.as_deref() == Some(*n))
}

Prevention

When it happens

Trigger: `result.schema.elements` has a different length, column names, or column types than the expected projection — e.g. the server ignored the projection, renamed columns, or returned a different type.

Common situations: Server/CLI version mismatch changing SQL result metadata; a custom server or proxy altering the schema; querying a non-standard endpoint that echoes a full-table schema.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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

Appendix: source

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

            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")?;
        }
        ensure!(
            row.last().unwrap().len() <= MAX_ENV_VALUE_BYTES,
            "Environment read value exceeds limit"
        );
    }
    match query {

View on GitHub (pinned to eddf9f5014)