{"record":{"id":"0ba6ade468ce9c27","repo":"tursodatabase/turso","slug":"query-did-not-return-a-row","errorCode":null,"errorMessage":"query did not return a row","messagePattern":"query did not return a row","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cli/app.rs","lineNumber":2386,"sourceCode":"    s.replace(\"''\", \"'\")\n}\n\nimpl Drop for Limbo {\n    fn drop(&mut self) {\n        self.save_history();\n        unsafe {\n            ManuallyDrop::drop(&mut self.input_buff);\n        }\n    }\n}\n\nfn fetch_single_i64(rows: &mut turso_core::Statement) -> anyhow::Result<i64> {\n    let mut result: Option<i64> = None;\n    rows.run_with_row_callback(|row| {\n        result = Some(row.get(0)?);\n        Ok(())\n    })?;\n    result.ok_or_else(|| anyhow!(\"query did not return a row\"))\n}\n\n/// Normalize `path?key=val` to `file:path?key=val` so query parameters\n/// are parsed as URI options (e.g. `?locking=shared_reads`) instead of\n/// being treated as part of the filename.\n///\n/// Only the *last* `?` that introduces a valid `key=value` query string is\n/// treated as the query separator. Earlier `?` characters are\n/// percent-encoded (`%3F`) so they remain part of the filename.\n/// A trailing `?` with no `key=value` pair is left alone (it is just part\n/// of the filename).\nfn normalize_db_path(db_file: String) -> String {\n    if db_file.starts_with(\"file:\") {\n        return db_file;\n    }\n\n    // Walk from the right to find the last '?' whose suffix looks like\n    // query parameters (contains at least one '=').","sourceCodeStart":2368,"sourceCodeEnd":2404,"githubUrl":"https://github.com/tursodatabase/turso/blob/492c4a71cd7c2649e7df83da1471b74f4b1c7aa9/cli/app.rs#L2368-L2404","documentation":"Returned by fetch_single_i64 when a statement expected to yield exactly one integer row produces zero rows (cli/app.rs:2370). The helper drives run_with_row_callback and collects the first column into an Option; the callback succeeds but never fires, so the Option stays None and this error is built.","triggerScenarios":"Calling fetch_single_i64 on a query with an empty result set: a PRAGMA that returns no rows in the current engine state, a WHERE clause filtering everything out, or a metadata query whose row output depends on engine version.","commonSituations":"PRAGMAs whose output shape changed between versions; single-row lookups against empty tables; predicates that stop matching after data changes.","solutions":["Run the exact query in the shell - if it returns no rows, fix the query or the data","For genuinely optional values, map the zero-row case to a default instead of propagating the error","Verify the PRAGMA or statement is supported and returns a row in this Turso version"],"exampleFix":"// before\nlet n: i64 = fetch_single_i64(&mut stmt)?; // errors on empty result\n// after\nlet n: i64 = match fetch_single_i64(&mut stmt) {\n    Ok(n) => n,\n    Err(e) if e.to_string().contains(\"did not return a row\") => 0,\n    Err(e) => return Err(e),\n};","handlingStrategy":"validation","validationCode":"let n: i64 = match fetch_single_i64(&mut stmt) {\n    Ok(n) => n,\n    Err(e) if e.to_string().contains(\"did not return a row\") => 0,\n    Err(e) => return Err(e),\n};","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Decide up front whether zero rows is an error or a default for each lookup","Test single-value queries against empty databases","Prefer an Option-returning variant for genuinely optional values"],"tags":["cli","query","empty-result","single-row","rust"],"backgroundTag":"empty-query-result","analyzedSha":"492c4a71cd7c2649e7df83da1471b74f4b1c7aa9","analyzedAt":"2026-08-20T07:02:18.389Z","contentChangedAt":"2026-08-20T07:02:18.389Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}