tursodatabase/turso · error
unexpected cursor type in op_column_range_fetch body ({other
Error message
unexpected cursor type in op_column_range_fetch body ({other:?}) What it means
op_column_range_fetch (bulk extraction of a column range into registers) matched a cursor kind it cannot handle — the catch-all arm after the B-tree record and pseudo-record cases. The opcode was emitted for a cursor that has no record payload to decode (sorter, virtual table, index-method, etc.), so the program is inconsistent with the cursor's kind.
Source
Thrown at core/vdbe/execute.rs:2504
let (left, right) = state.registers.split_at_mut(dest + count);
(&mut right[content_reg - (dest + count)], &mut left[dest..])
};
match content {
Register::Record(record) => {
let filled = record
.iter()?
.decode_into_registers_after(start_column, dest_regs)?;
if filled < count {
crate::bail_parse_error!("pseudo-cursor column out of range for record");
}
}
other => {
crate::bail_parse_error!("non-register register in pseudo-record ({other:?})")
}
}
}
other => {
panic!("unexpected cursor type in op_column_range_fetch body ({other:?})")
}
}
Ok(InsnFunctionStepResult::Step)
}
pub fn op_column_has_field(
program: &Program,
state: &mut ProgramState,
insn: &Insn,
_pager: &Arc<Pager>,
) -> InsnResult {
load_insn!(
ColumnHasField {
cursor_id,
column,
target_pc,
},
insnView on GitHub (pinned to 492c4a71cd)
Solutions
- Report with SQL — the range-fetch opcode must only target record-backed cursors
- Narrow the selected column list to see whether the plan falls back to per-column Column opcodes
- Move the wide projection into its own query level
- Upgrade
Defensive patterns
Strategy: type-guard
Validate before calling
// range fetch requires a record-backed cursor
if let Insn::ColumnRangeFetch { cursor_id, .. } = insn {
match program.cursor_ref.get(*cursor_id).map(|(_, t)| t) {
Some(CursorType::BTreeTable(_)) | Some(CursorType::BTreeIndex(_)) | Some(CursorType::Pseudo(_)) => {}
other => crate::bail_parse_error!("ColumnRangeFetch on non-record cursor ({other:?})"),
}
} Type guard
fn record_backed(t: &CursorType) -> bool {
matches!(t, CursorType::BTreeTable(_) | CursorType::BTreeIndex(_) | CursorType::Pseudo(_))
} Prevention
- Keep wide-projection queries over vtabs/sorters in the regression corpus
- Narrow projections when a new engine version enables bulk column fetch
- Report with the exact column list that triggers it
When it happens
Trigger: Plans using the bulk column-range fetch (wide column lists) where the target cursor was allocated as a sorter or vtab cursor — commonly after subquery flattening, or when column-range emission was extended to new statement shapes.
Common situations: Wide SELECT lists over many columns; queries over vtabs or sorted subqueries after upgrades enabling the column-range opcode.
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/28779a6710c49bbf.
Report an issue: GitHub.