tursodatabase/turso · error
RowKey::Record requires Index cursor type
Error message
RowKey::Record requires Index cursor type
What it means
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'.
Source
Thrown at core/mvcc/cursor.rs:1523
Ok(IOResult::Done(()))
}
fn rowid(&mut self) -> IOResultOr<Option<i64>> {
if self.get_null_flag() {
return Ok(IOResult::Done(None));
}
let rowid = match self.get_current_pos() {
CursorPosition::Loaded {
row_id,
in_btree: _,
..
} => match &row_id.row_id {
RowKey::Int(id) => Some(*id),
RowKey::Record(sortable_key) => {
// For index cursors, the rowid is stored in the last column of the index record
let MvccCursorType::Index(index_info) = &self.mv_cursor_type else {
panic!("RowKey::Record requires Index cursor type");
};
if index_info.has_rowid {
match sortable_key.key.last_value() {
Some(Ok(crate::types::ValueRef::Numeric(
crate::numeric::Numeric::Integer(rowid),
))) => Some(rowid),
_ => {
crate::bail_parse_error!("Failed to parse rowid from index record")
}
}
} else {
crate::bail_parse_error!("Indexes without rowid are not supported in MVCC");
}
}
},
CursorPosition::BeforeFirst => None,
CursorPosition::End => None,
};View on GitHub (pinned to 492c4a71cd)
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
Example fix
// before
let rowid = extract_rowid(&table_cursor); // RowKey::Record on a Table cursor -> panic
// after
let rowid = match cursor_type {
MvccCursorType::Index(_) => extract_rowid_from_index(cursor),
MvccCursorType::Table => extract_rowid_int(cursor),
}; Defensive patterns
Strategy: type-guard
Validate before calling
if let MvccCursorType::Index(info) = cursor_type {
if !info.has_rowid { crate::bail_parse_error!("index without rowid"); }
// only now read the rowid from RowKey::Record
} Type guard
fn is_index_cursor(t: &MvccCursorType) -> bool {
matches!(t, MvccCursorType::Index(_))
} Prevention
- Branch rowid extraction on the cursor type before touching RowKey::Record
- Remember MVCC does not support rowid-less indexes or WITHOUT ROWID tables
When it happens
Trigger: 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).
Common situations: MVCC workloads mixing WITHOUT ROWID tables or covering-index plans; contributor changes to cursor typing.
Related errors
- SeekKey::IndexKey requires Index cursor type
- invalid position to read current mvcc row
- Invalid btree seek state in seek_btree_and_set_peek: {:?}
- Cursor not found: {key:?}
- Cursor not found: {cursor_id}
AI-assisted analysis of tursodatabase/turso@492c4a71cd (2026-08-20).
Data as JSON: /api/errors/cd4145bf13e111eb.
Report an issue: GitHub.