tursodatabase/turso · error
invalid position to read current mvcc row
Error message
invalid position to read current mvcc row
What it means
MvccCursor::read_mvcc_current_row is only valid while the cursor sits at CursorPosition::Loaded with in_btree == false - positioned by the MVCC scan path where the row's version chain is already resolved. Calling it at Start/End, at an in-btree position, or before advancing panics; it is an internal API-contract check in core/mvcc.
Source
Thrown at core/mvcc/cursor.rs:726
})?;
Ok(IOResult::Done(Some(record_ref)))
}
CursorPosition::BeforeFirst => {
// Before first is not a valid position, so we return none.
Ok(IOResult::Done(None))
}
CursorPosition::End => Ok(IOResult::Done(None)),
}
}
pub fn read_mvcc_current_row(&self) -> Result<Option<Row>> {
let (row_id, versions) = match &self.current_pos {
CursorPosition::Loaded {
row_id,
in_btree,
versions,
} if !in_btree => (row_id, versions),
_ => panic!("invalid position to read current mvcc row"),
};
// Scan path: the range iterator already resolved this row's version
// chain, so read it directly instead of a second skiplist lookup.
if let Some(versions) = versions {
return self.db.read_visible_from_versions(self.tx_id, versions);
}
let maybe_index_id = match &self.mv_cursor_type {
MvccCursorType::Index(_) => Some(self.table_id),
MvccCursorType::Table => None,
};
self.db
.read_from_table_or_index(self.tx_id, row_id, maybe_index_id)
}
pub fn close(self) -> Result<()> {
Ok(())
}
View on GitHub (pinned to 492c4a71cd)
Solutions
- Advance the cursor (next) until it reports a row before reading
- Branch on the current position and only read when Loaded with in_btree == false
- If reached without touching core code, report with the query and MVCC setup
Example fix
// before
let row = cursor.read_mvcc_current_row()?; // called before any next()
// after
while let IOResult::Done(Some(_)) = return_if_io!(cursor.next()) {
if let Some(row) = cursor.read_mvcc_current_row()? { /* consume row */ }
} Defensive patterns
Strategy: validation
Validate before calling
// only read the current row while positioned by the scan path
match cursor.get_current_pos() {
CursorPosition::Loaded { in_btree: false, .. } => cursor.read_mvcc_current_row(),
_ => Ok(None),
} Prevention
- read_mvcc_current_row is a post-advance API: always step the cursor first
- In review, keep position-shape checks adjacent to MVCC cursor call sites
When it happens
Trigger: Executor code calling read_mvcc_current_row before the first next() step, after exhaustion, or while the cursor is dual-positioned in the btree half of the MVCC cursor.
Common situations: Contributor changes to MVCC cursor stepping; new scan operators reusing the cursor API incorrectly.
Related errors
- Invalid btree seek state in seek_btree_and_set_peek: {:?}
- RowKey::Record requires Index cursor type
- SeekKey::IndexKey requires Index cursor type
- Cursor not found: {key:?}
- DB should not be initialized and should not do any IO
AI-assisted analysis of tursodatabase/turso@492c4a71cd (2026-08-20).
Data as JSON: /api/errors/1fd9c2dca513aac6.
Report an issue: GitHub.