tursodatabase/turso · error
OpenRead on sorter cursor
Error message
OpenRead on sorter cursor
What it means
Insn::OpenRead executed on a cursor whose type is CursorType::Sorter. Sorter cursors are ephemeral row stores filled by SorterInsert for ORDER BY / GROUP BY / DISTINCT processing and are never backed by a database B-tree, so OpenRead is meaningless on them. The bytecode program used a sorter cursor id where a B-tree cursor was intended — a codegen inconsistency, panicked inside op_open_read.
Source
Thrown at core/vdbe/execute.rs:1451
num_columns,
)?;
let index_info = Arc::new(if let Some(mv_store) = mv_store.as_ref() {
IndexInfo::new_from_index_in(index, mv_store.allocator())?
} else {
IndexInfo::new_from_index(index)?
});
let cursor =
maybe_promote_to_mvcc_cursor(btree_cursor, MvccCursorType::Index(index_info))?;
cursors
.get_mut(*cursor_id)
.expect("cursor_id should be valid")
.replace(cursor.into_cursor());
}
CursorType::Pseudo(_) => {
panic!("OpenRead on pseudo cursor");
}
CursorType::Sorter => {
panic!("OpenRead on sorter cursor");
}
CursorType::IndexMethod(..) => {
unreachable!("IndexMethod handled above")
}
CursorType::VirtualTable(_) => {
panic!("OpenRead on virtual table cursor, use Insn:VOpen instead");
}
}
state.pc += 1;
Ok(InsnFunctionStepResult::Step)
}
pub fn op_vopen(
program: &Program,
state: &mut ProgramState,
insn: &Insn,
_pager: &Arc<Pager>,
) -> InsnResult {View on GitHub (pinned to 492c4a71cd)
Solutions
- Report the SQL — the sorter cursor id must not flow into an OpenRead emission
- Confirm the trigger by removing ORDER BY / DISTINCT and re-running; then attach both plans to the bug
- Rewrite the query to sort in an outer query level so sorter and table cursors do not mix
- Upgrade
Defensive patterns
Strategy: validation
Validate before calling
// reuse the program audit: flag OpenRead against sorter cursors before execution
for insn in &program.insns {
if let Insn::OpenRead { cursor_id, .. } = insn {
if matches!(program.cursor_ref.get(*cursor_id).map(|(_, t)| t), Some(CursorType::Sorter)) {
crate::bail_parse_error!("OpenRead targets sorter cursor");
}
}
} Prevention
- Include ORDER BY/DISTINCT plus join/subquery combinations in CI query corpora
- Audit emitted programs for OpenRead on sorter cursors in debug builds
- Catch engine panics per-statement at the embedding boundary
When it happens
Trigger: ORDER BY / GROUP BY / DISTINCT queries whose sorter cursor id is reused or mis-resolved by a later OpenRead emission; cursor renumbering changes; scalar subqueries inside sorted outer queries where sorter and table cursor ids cross.
Common situations: Queries combining ORDER BY or DISTINCT with joins/subqueries; engine upgrades or planner changes that reallocated sorter cursor ids.
Related errors
- OpenRead on pseudo cursor
- Rewind on non-btree/materialized-view cursor
- unexpected cursor type
- Next on non-btree/materialized-view cursor
- {} on unexpected cursor
AI-assisted analysis of tursodatabase/turso@492c4a71cd (2026-08-20).
Data as JSON: /api/errors/66fe727752415292.
Report an issue: GitHub.