{"record":{"id":"fbfa2f9393df0871","repo":"tursodatabase/turso","slug":"unexpected-cursor-type","errorCode":null,"errorMessage":"unexpected cursor type","messagePattern":"unexpected cursor type","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/vdbe/execute.rs","lineNumber":1986,"sourceCode":"                if let Some(deferred) = state.deferred_seeks[cursor_id].take() {\n                    *state.active_op_state.column() = OpColumnState::Rowid {\n                        index_cursor_id: deferred.index_cursor_id,\n                        table_cursor_id: deferred.table_cursor_id,\n                    };\n                } else {\n                    *state.active_op_state.column() = OpColumnState::GetColumn;\n                }\n            }\n            OpColumnState::Rowid {\n                index_cursor_id,\n                table_cursor_id,\n            } => {\n                let Some(rowid) = ({\n                    let index_cursor = state.get_cursor(index_cursor_id);\n                    match index_cursor {\n                        Cursor::BTree(cursor) => return_if_io!(cursor.rowid()),\n                        Cursor::IndexMethod(cursor) => return_if_io!(cursor.query_rowid()),\n                        _ => panic!(\"unexpected cursor type\"),\n                    }\n                }) else {\n                    fetch.write_null_regs(state);\n                    break 'outer;\n                };\n                *state.active_op_state.column() = OpColumnState::Seek {\n                    rowid,\n                    table_cursor_id,\n                };\n            }\n            OpColumnState::Seek {\n                rowid,\n                table_cursor_id,\n            } => {\n                {\n                    let table_cursor = state.get_cursor(table_cursor_id);\n                    // MaterializedView cursors shouldn't go through deferred seek logic\n                    // but if we somehow get here, handle it appropriately","sourceCodeStart":1968,"sourceCodeEnd":2004,"githubUrl":"https://github.com/tursodatabase/turso/blob/6c7252267988c76e632af00a671e4b9788dfae13/core/vdbe/execute.rs#L1968-L2004","documentation":"Inside op_column's resumable state machine, the Rowid state reads the current rowid from the index cursor before seeking the paired table cursor. The panic fires when that cursor is neither Cursor::BTree nor Cursor::IndexMethod at runtime — the bytecode arranged a rowid fetch through a cursor kind that cannot supply one (sorter, pseudo, virtual table). An internal program inconsistency hit mid-execution.","triggerScenarios":"Column-extraction plans that pair an index cursor with a table cursor (index scan then row lookup) where the index slot actually holds a sorter/pseudo/vtab cursor — typically after cursor renumbering, or when index-method cursors are mis-tagged in the plan.","commonSituations":"Plan flips between covering-index and table-lookup access paths; custom index-method features; engine upgrades changing index cursor handling.","solutions":["Report with SQL and EXPLAIN — the index-cursor slot holds an incompatible kind at runtime","Force a different plan (drop/disable the index or use NOT INDEXED) so the paired-cursor path is not used","Rewrite the index-driven lookup as a join to change the access path","Upgrade"],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":"// before entering the paired index/table column path, verify the index slot kind\nif !matches!(\n    program.cursor_ref.get(index_cursor_id).map(|(_, t)| t),\n    Some(CursorType::BTreeIndex(_)) | Some(CursorType::IndexMethod(..))\n) {\n    crate::bail_parse_error!(\"index cursor {index_cursor_id} cannot supply a rowid\");\n}","typeGuard":"fn rowid_capable(t: &CursorType) -> bool {\n    matches!(t, CursorType::BTreeIndex(_) | CursorType::IndexMethod(..))\n}","tryCatchPattern":null,"preventionTips":["Cover covering-index vs table-lookup plan switches in conformance tests","If using custom index methods, test them through the paired-cursor column path","Report reproducible cases with EXPLAIN output"],"tags":["vdbe","executor","op-column","cursor-type","rowid","panic","runtime"],"backgroundTag":"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"}