{"record":{"id":"ba4e21246440b2bb","repo":"tursodatabase/turso","slug":"query-did-not-return-a-json-plan","errorCode":null,"errorMessage":"query {} did not return a JSON plan","messagePattern":"query (.+?) did not return a JSON plan","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"perf/join-benchmark/main.rs","lineNumber":182,"sourceCode":"\nfn execute(database: &Database, statement: &mut turso_core::Statement) -> Result<u64> {\n    let mut result_rows = 0_u64;\n    loop {\n        match statement.step()? {\n            StepResult::Row => result_rows = result_rows.saturating_add(1),\n            StepResult::IO | StepResult::Yield | StepResult::Sleep { .. } => database.io.step()?,\n            StepResult::Done => return Ok(result_rows),\n            StepResult::Interrupt => bail!(\"query was interrupted\"),\n            StepResult::Busy => bail!(\"database was busy\"),\n        }\n    }\n}\n\nfn print_plan(connection: &Arc<turso_core::Connection>, query: &Query) -> Result<()> {\n    let sql = format!(\"EXPLAIN QUERY PLAN FORMAT=JSON {}\", query.sql);\n    let rows = connection.prepare(sql)?.run_collect_rows()?;\n    let Some(Value::Text(plan)) = rows.first().and_then(|row| row.first()) else {\n        bail!(\"query {} did not return a JSON plan\", query.name);\n    };\n    let plan: JsonValue = serde_json::from_str(plan.as_str())?;\n    println!(\"{}\", json!({\"query\": query.name, \"plan\": plan}));\n    Ok(())\n}\n","sourceCodeStart":164,"sourceCodeEnd":188,"githubUrl":"https://github.com/tursodatabase/turso/blob/492c4a71cd7c2649e7df83da1471b74f4b1c7aa9/perf/join-benchmark/main.rs#L164-L188","documentation":"print_plan runs `EXPLAIN QUERY PLAN FORMAT=JSON <query>` and expects the first cell of the first row to be a Text value containing the JSON plan. If there are no rows, the row is empty, or the value is not Text (e.g. NULL or a blob), it fails with this error naming the query.","triggerScenarios":"Calling print_plan for a query whose EXPLAIN QUERY PLAN FORMAT=JSON produced no output rows or a non-text first column — e.g. the query references a missing table so planning yields no plan, or the FORMAT=JSON option isn't supported so output shape differs.","commonSituations":"Query SQL referring to a table that doesn't exist in the benchmark database; older engine build without FORMAT=JSON support; prepare/run failing silently and returning an empty row set.","solutions":["Run the query manually in tursodb: `EXPLAIN QUERY PLAN FORMAT=JSON <sql>;` to see what it returns.","Fix the query SQL (missing/misspelled tables) so a plan is produced.","Confirm the engine build supports EXPLAIN QUERY PLAN FORMAT=JSON; upgrade or drop the FORMAT clause.","Check run_collect_rows results for errors swallowed upstream before the pattern match."],"exampleFix":"// before\nlet sql = format!(\"EXPLAIN QUERY PLAN FORMAT=JSON {}\", query.sql);\n// after\n// verify the statement first\nconnection.prepare(query.sql.clone())?.run_collect_rows()?;\nlet sql = format!(\"EXPLAIN QUERY PLAN FORMAT=JSON {}\", query.sql);","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"let rows = connection.prepare(sql)?.run_collect_rows()?;\nlet plan_text = rows.first().and_then(|r| r.first())\n    .and_then(|v| if let Value::Text(t) = v { Some(t.clone()) } else { None });\nmatch plan_text {\n    Some(t) => println!(\"{}\", t),\n    None => eprintln!(\"skipping plan for {} (no JSON plan returned)\", query.name),\n}","preventionTips":["Validate all query SQL references existing tables before benchmarking","Confirm the engine build supports EXPLAIN QUERY PLAN FORMAT=JSON","Spot-check one EXPLAIN QUERY PLAN output manually before batch runs"],"tags":["rust","benchmark","explain","unexpected-response"],"backgroundTag":"unexpected-response-shape","analyzedSha":"492c4a71cd7c2649e7df83da1471b74f4b1c7aa9","analyzedAt":"2026-09-13T18:13:59.796Z","contentChangedAt":"2026-09-13T18:13:59.796Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}