{"record":{"id":"5318a681bc497d42","repo":"clockworklabs/SpacetimeDB","slug":"invalid-environment-read-row","errorCode":null,"errorMessage":"Invalid environment read row","messagePattern":"Invalid environment read row","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/cli/src/subcommands/env.rs","lineNumber":138,"sourceCode":"    // Validate the requested projection before rendering any response values.\n    let results: Vec<spacetimedb_client_api_messages::http::SqlStmtResult<Vec<String>>> =\n        serde_json::from_slice(body).map_err(|_| anyhow::anyhow!(\"Invalid environment read response\"))?;\n    ensure!(results.len() == 1, \"Invalid environment read result count\");\n    let result = &results[0];\n    let expected: &[&str] = match query {\n        Query::List => &[\"key\", \"value\"],\n        Query::Get(_) => &[\"value\"],\n    };\n    ensure!(\n        result.schema.elements.len() == expected.len()\n            && result.schema.elements.iter().zip(expected).all(|(column, name)| {\n                column.name.as_deref() == Some(*name) && column.algebraic_type == spacetimedb_lib::AlgebraicType::String\n            }),\n        \"Invalid environment read projection\"\n    );\n    ensure!(result.rows.len() <= MAX_ENV_VARS, \"Environment key count exceeds limit\");\n    for row in &result.rows {\n        ensure!(row.len() == expected.len(), \"Invalid environment read row\");\n        if matches!(query, Query::List) {\n            validate_key(&row[0]).context(\"Invalid environment key in response\")?;\n        }\n        ensure!(\n            row.last().unwrap().len() <= MAX_ENV_VALUE_BYTES,\n            \"Environment read value exceeds limit\"\n        );\n    }\n    match query {\n        Query::List => {\n            let mut rows: Vec<_> = result.rows.iter().collect();\n            rows.sort_unstable_by(|a, b| a[0].cmp(&b[0]));\n            let rows = rows.into_iter().map(|row| {\n                Ok::<_, std::convert::Infallible>(spacetimedb_lib::sats::product![row[0].as_str(), row[1].as_str()])\n            });\n            let table = sql::build_table(\n                spacetimedb_lib::sats::satn::PsqlClient::SpacetimeDB,\n                &result.schema,","sourceCodeStart":120,"sourceCodeEnd":156,"githubUrl":"https://github.com/clockworklabs/SpacetimeDB/blob/eddf9f5014579a50d4b67630e28b6e15cad9c4af/crates/cli/src/subcommands/env.rs#L120-L156","documentation":"Thrown by `render` when a row in the environment-read result has a column count different from the expected projection width (2 for `key`/`value` list queries, 1 for `value`-only get queries). It guards row access before reading row[0] and row.last().","triggerScenarios":"A parsed row vector's length differs from `expected.len()` — the server returned malformed rows, or the schema/row shapes disagree due to a protocol mismatch.","commonSituations":"Server/CLI version mismatch; corrupt or hand-modified SQL response from a proxy; a server bug emitting short rows.","solutions":["Match CLI and server versions to restore row-shape compatibility.","Inspect the raw JSON response to confirm row arity.","Remove any intermediary that may be transforming the SQL response.","Retry to rule out a transient serialization glitch."],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":"fn rows_are_well_formed(r: &SqlStmtResult<Vec<String>>, width: usize) -> bool {\n    r.rows.iter().all(|row| row.len() == width)\n}","tryCatchPattern":null,"preventionTips":["Keep CLI and server versions compatible.","Validate row arity when consuming SQL responses programmatically.","Avoid proxies that reshape responses."],"tags":["cli","spacetimedb","response-parsing","validation"],"backgroundTag":"unexpected-response-shape","analyzedSha":"eddf9f5014579a50d4b67630e28b6e15cad9c4af","analyzedAt":"2026-09-20T12:15:59.611Z","contentChangedAt":"2026-09-20T12:15:59.611Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}