{"record":{"id":"74795af3d86c562d","repo":"tursodatabase/turso","slug":"openread-on-pseudo-cursor","errorCode":null,"errorMessage":"OpenRead on pseudo cursor","messagePattern":"OpenRead on pseudo cursor","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/vdbe/execute.rs","lineNumber":1379,"sourceCode":"                pager,\n                maybe_transform_root_page_to_positive(mv_store.as_ref(), *root_page),\n                index.as_ref(),\n                num_columns,\n            )?);\n            let index_info = Arc::new(if let Some(mv_store) = mv_store.as_ref() {\n                IndexInfo::new_from_index_in(index, mv_store.allocator())?\n            } else {\n                IndexInfo::new_from_index(index)?\n            });\n            let cursor =\n                maybe_promote_to_mvcc_cursor(btree_cursor, MvccCursorType::Index(index_info))?;\n            cursors\n                .get_mut(*cursor_id)\n                .expect(\"cursor_id should be valid\")\n                .replace(Cursor::new_btree(cursor));\n        }\n        CursorType::Pseudo(_) => {\n            panic!(\"OpenRead on pseudo cursor\");\n        }\n        CursorType::Sorter => {\n            panic!(\"OpenRead on sorter cursor\");\n        }\n        CursorType::IndexMethod(..) => {\n            unreachable!(\"IndexMethod handled above\")\n        }\n        CursorType::VirtualTable(_) => {\n            panic!(\"OpenRead on virtual table cursor, use Insn:VOpen instead\");\n        }\n    }\n    state.pc += 1;\n    Ok(InsnFunctionStepResult::Step)\n}\n\npub fn op_vopen(\n    program: &Program,\n    state: &mut ProgramState,","sourceCodeStart":1361,"sourceCodeEnd":1397,"githubUrl":"https://github.com/tursodatabase/turso/blob/6c7252267988c76e632af00a671e4b9788dfae13/core/vdbe/execute.rs#L1361-L1397","documentation":"At execution time Insn::OpenRead tried to open a cursor slot whose cursor_ref type is CursorType::Pseudo. Pseudo cursors hold one materialized in-memory row (used for VALUES rows and co-routine output) and have no B-tree to open, so OpenRead cannot apply. The bytecode reused a pseudo cursor id as if it were a B-tree cursor — a translation bug, hit inside op_open_read while stepping the program.","triggerScenarios":"A plan that materializes rows into a pseudo cursor and later emits OpenRead for the same cursor id — typically after cursor renumbering/reallocation changes, or when a co-routine or VALUES-clause pseudo cursor id leaks into an outer open-table sequence.","commonSituations":"Queries combining VALUES clauses, co-routine subqueries, or CTE materialization with ordinary table scans; engine versions where cursor allocation was refactored.","solutions":["Report the SQL — OpenRead may only target BTreeTable/BTreeIndex/MaterializedView cursors; the translator allocated the wrong kind","Rewrite the VALUES/co-routine construct into a real temp table or plain SELECT to avoid pseudo cursors","Upgrade to a version with the cursor-allocation fix"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// audit a compiled program before first execution: OpenRead must target btree-backed cursors\nfn audit_open_reads(program: &Program) -> Result<()> {\n    for insn in &program.insns {\n        if let Insn::OpenRead { cursor_id, .. } = insn {\n            match program.cursor_ref.get(*cursor_id).map(|(_, t)| t) {\n                Some(CursorType::BTreeTable(_)) | Some(CursorType::BTreeIndex(_))\n                | Some(CursorType::MaterializedView(..)) => {}\n                other => crate::bail_parse_error!(\"OpenRead targets non-btree cursor ({other:?})\"),\n            }\n        }\n    }\n    Ok(())\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Run a bytecode audit pass in debug builds that type-checks every cursor-consuming insn against cursor_ref","Wrap statement execution in catch_unwind at your API boundary so engine panics become per-query errors, not process crashes","Keep regression tests mixing VALUES/CTE materialization with table scans"],"tags":["vdbe","executor","cursor-type","pseudo-cursor","panic","runtime"],"backgroundTag":"bytecode-cursor-type-mismatch","analyzedSha":"6c7252267988c76e632af00a671e4b9788dfae13","analyzedAt":"2026-08-20T07:02:18.389Z","contentChangedAt":"2026-08-20T07:02:18.389Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}