{"record":{"id":"cd4145bf13e111eb","repo":"tursodatabase/turso","slug":"rowkey-record-requires-index-cursor-type","errorCode":null,"errorMessage":"RowKey::Record requires Index cursor type","messagePattern":"RowKey::Record requires Index cursor type","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/mvcc/cursor.rs","lineNumber":1523,"sourceCode":"\n        Ok(IOResult::Done(()))\n    }\n\n    fn rowid(&mut self) -> IOResultOr<Option<i64>> {\n        if self.get_null_flag() {\n            return Ok(IOResult::Done(None));\n        }\n        let rowid = match self.get_current_pos() {\n            CursorPosition::Loaded {\n                row_id,\n                in_btree: _,\n                ..\n            } => match &row_id.row_id {\n                RowKey::Int(id) => Some(*id),\n                RowKey::Record(sortable_key) => {\n                    // For index cursors, the rowid is stored in the last column of the index record\n                    let MvccCursorType::Index(index_info) = &self.mv_cursor_type else {\n                        panic!(\"RowKey::Record requires Index cursor type\");\n                    };\n                    if index_info.has_rowid {\n                        match sortable_key.key.last_value() {\n                            Some(Ok(crate::types::ValueRef::Numeric(\n                                crate::numeric::Numeric::Integer(rowid),\n                            ))) => Some(rowid),\n                            _ => {\n                                crate::bail_parse_error!(\"Failed to parse rowid from index record\")\n                            }\n                        }\n                    } else {\n                        crate::bail_parse_error!(\"Indexes without rowid are not supported in MVCC\");\n                    }\n                }\n            },\n            CursorPosition::BeforeFirst => None,\n            CursorPosition::End => None,\n        };","sourceCodeStart":1505,"sourceCodeEnd":1541,"githubUrl":"https://github.com/tursodatabase/turso/blob/492c4a71cd7c2649e7df83da1471b74f4b1c7aa9/core/mvcc/cursor.rs#L1505-L1541","documentation":"When an MVCC cursor's current key is RowKey::Record (index or WITHOUT ROWID-style record), the rowid is recovered from the last column of the index record - which only exists for index cursors (MvccCursorType::Index with has_rowid). On a table cursor this panics; for rowid-less indexes the code instead bails with 'Indexes without rowid are not supported in MVCC'.","triggerScenarios":"Internal: rowid extraction from get_current_pos invoked on a Table-type cursor whose key ended up as RowKey::Record, or on index cursors whose has_rowid is false (which returns a parse error instead).","commonSituations":"MVCC workloads mixing WITHOUT ROWID tables or covering-index plans; contributor changes to cursor typing.","solutions":["Ensure record-keyed access only goes through cursors opened as MvccCursorType::Index","Avoid WITHOUT ROWID tables and rowid-less indexes under experimental MVCC until supported","If hit from SQL, capture the EXPLAIN plan and report it"],"exampleFix":"// before\nlet rowid = extract_rowid(&table_cursor); // RowKey::Record on a Table cursor -> panic\n\n// after\nlet rowid = match cursor_type {\n    MvccCursorType::Index(_) => extract_rowid_from_index(cursor),\n    MvccCursorType::Table => extract_rowid_int(cursor),\n};","handlingStrategy":"type-guard","validationCode":"if let MvccCursorType::Index(info) = cursor_type {\n    if !info.has_rowid { crate::bail_parse_error!(\"index without rowid\"); }\n    // only now read the rowid from RowKey::Record\n}","typeGuard":"fn is_index_cursor(t: &MvccCursorType) -> bool {\n    matches!(t, MvccCursorType::Index(_))\n}","tryCatchPattern":null,"preventionTips":["Branch rowid extraction on the cursor type before touching RowKey::Record","Remember MVCC does not support rowid-less indexes or WITHOUT ROWID tables"],"tags":["mvcc","cursor","index","rowid","internal","panic"],"backgroundTag":"cursor-type-mismatch","analyzedSha":"492c4a71cd7c2649e7df83da1471b74f4b1c7aa9","analyzedAt":"2026-08-20T07:02:18.389Z","contentChangedAt":"2026-08-20T07:02:18.389Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}