clockworklabs/SpacetimeDB · error
Invalid environment read result count
Error message
Invalid environment read result count
What it means
Thrown by `render` when the parsed JSON body is valid `SqlStmtResult` JSON but the top-level array does not contain exactly one statement result. The environment read always issues a single SQL statement, so any other count indicates a protocol mismatch.
Solutions
- Align CLI and server versions so the SQL response protocol matches.
- Retry the command to rule out a transient server-side glitch.
- If you control a proxy, ensure it passes the SQL response through unmodified.
Defensive patterns
Strategy: validation
Type guard
fn is_single_result(r: &[SqlStmtResult<Vec<String>>]) -> bool { r.len() == 1 } Prevention
- Match CLI and server protocol versions.
- Pass SQL responses through proxies unmodified.
- Retry on transient server errors that could yield empty results.
When it happens
Trigger: `serde_json` succeeds but `results.len() != 1` — e.g. an empty array from a server that dropped the statement, or multiple results from an incompatible/newer server API.
Common situations: Running a CLI built against a different protocol version than the server; custom proxies splitting statements; server bug returning zero results for the env query.
Related errors
- Invalid environment read response
- Invalid environment read row
- Cannot extract accessor name from query
- Cannot extract table name from query
- Cannot semijoin a table to itself
AI-assisted analysis of clockworklabs/SpacetimeDB@eddf9f5014 (2026-09-20).
Data as JSON: /api/errors/8dc110220810de81.
Report an issue: GitHub.
Appendix: source
Thrown at crates/cli/src/subcommands/env.rs:123
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)