tursodatabase/turso · error · anyhow::Error
invalid response shape
Error message
invalid response shape
What it means
Thrown by TursoServer::db_sql when results[0] is ok but the element at response.result.rows is missing or not a JSON array (bindings/rust/src/sync.rs:1208). The server answered successfully, but the response does not match the shape the harness expects for a row set.
Source
Thrown at bindings/rust/src/sync.rs:1305
"requests": [{
"type": "execute",
"stmt": { "sql": sql }
}]
}))
.send()
.await?
.error_for_status()?;
let value: serde_json::Value = resp.json().await?;
let result = &value["results"][0];
if result["type"] != "ok" {
return Err(anyhow!("remote sql execution failed: {value}"));
}
let rows = result["response"]["result"]["rows"]
.as_array()
.ok_or_else(|| anyhow!("invalid response shape"))?;
Ok(rows
.iter()
.map(|row| {
row.as_array()
.unwrap()
.iter()
.map(|cell| match cell["value"].clone() {
serde_json::Value::Null => Value::Null,
serde_json::Value::Number(number) => {
if number.is_i64() {
Value::Integer(number.as_i64().unwrap())
} else {
Value::Real(number.as_f64().unwrap())
}
}
serde_json::Value::String(s) => Value::Text(s),
_ => panic!("unexpected json output"),View on GitHub (pinned to 492c4a71cd)
Solutions
- Print the full response value before the shape check to see what the server actually returned
- Rebuild both the sync server binary and the bindings crate from the same commit
- Run the tests from a single workspace checkout so client and server versions match
- If the statement is non-query, use an execution helper that does not expect rows
Example fix
// before
let rows = result["response"]["result"]["rows"]
.as_array()
.ok_or_else(|| anyhow!("invalid response shape"))?;
// after
let Some(rows) = result["response"]["result"]["rows"].as_array() else {
anyhow::bail!("unexpected response: {value}");
}; Defensive patterns
Strategy: type-guard
Validate before calling
let value: serde_json::Value = resp.json().await?;
anyhow::ensure!(has_row_array(&value), "unexpected sync response: {value}"); Type guard
fn has_row_array(v: &serde_json::Value) -> bool {
v["results"][0]["response"]["result"]["rows"].is_array()
} Prevention
- Validate the response shape before indexing into it
- Pin harness and server to the same commit in CI
- Print the raw response when the shape check fails so drift is obvious
When it happens
Trigger: Server version that returns a different response schema (renamed fields, rows nested elsewhere); a statement type that legitimately returns no rows object; response format changed on one side of a client/server version skew.
Common situations: Harness and server built from different commits during a bisect; the Hrana/sync response format evolved in core without updating the bindings test harness; a new statement kind added server-side.
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
- request failed: {status} {text}
- local sync server on port {port} did not become ready within
- local sync server failed to start after {SPAWN_ATTEMPTS} att
- remote sql execution failed: {value}
- failed to build IO runtime
AI-assisted analysis of tursodatabase/turso@492c4a71cd (2026-08-20).
Data as JSON: /api/errors/9bcbcf1d72356fd4.
Report an issue: GitHub.