{"record":{"id":"a2131ec95a1921c8","repo":"transact-rs/sqlx","slug":"invalid-column-index","errorCode":null,"errorMessage":"invalid column index: {}","messagePattern":"invalid column index: (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"sqlx-sqlite/src/statement/handle.rs","lineNumber":51,"sourceCode":"unsafe impl Send for StatementHandle {}\n\n// Most of the getters below allocate internally, and unsynchronized access is undefined.\n// unsafe impl !Sync for StatementHandle {}\n\nmacro_rules! expect_ret_valid {\n    ($fn_name:ident($($args:tt)*)) => {{\n        let val = $fn_name($($args)*);\n\n        TryFrom::try_from(val)\n            // This likely means UB in SQLite itself or our usage of it;\n            // signed integer overflow is UB in the C standard.\n            .unwrap_or_else(|_| panic!(\"{}() returned invalid value: {val:?}\", stringify!($fn_name)))\n    }}\n}\n\nmacro_rules! check_col_idx {\n    ($idx:ident) => {\n        c_int::try_from($idx).unwrap_or_else(|_| panic!(\"invalid column index: {}\", $idx))\n    };\n}\n\n// might use some of this later\n#[allow(dead_code)]\nimpl StatementHandle {\n    pub(super) fn new(ptr: NonNull<sqlite3_stmt>) -> Self {\n        Self(ptr)\n    }\n\n    #[inline]\n    pub(super) unsafe fn db_handle(&self) -> *mut sqlite3 {\n        // O(c) access to the connection handle for this statement handle\n        // https://sqlite.org/c3ref/db_handle.html\n        sqlite3_db_handle(self.0.as_ptr())\n    }\n\n    pub(crate) fn read_only(&self) -> bool {","sourceCodeStart":33,"sourceCodeEnd":69,"githubUrl":"https://github.com/transact-rs/sqlx/blob/03af8bcc5711a1935580a54bea249c219a0c217d/sqlx-sqlite/src/statement/handle.rs#L33-L69","documentation":"In the SQLite driver, the check_col_idx! macro (sqlx-sqlite/src/statement/handle.rs) panics when a column index passed to a StatementHandle accessor cannot be converted to a C `c_int` — i.e. the index is negative or exceeds the c_int range. The sqlite3 C API takes an `int` column index, so any out-of-range Rust usize/i64 index is rejected before reaching SQLite. Reaching this means an internal caller used an invalid column ordinal.","triggerScenarios":"Any SQLite code path (column name/type/value lookups in the driver) indexing a statement with a negative or huge index; realistically surfaced by driver bugs or by a `try_get`/`try_get_raw` call whose computed column index overflowed (e.g. from a corrupted ColumnIndex or row with an unexpectedly large index).","commonSituations":"Users typically see this indirectly: a get(\"col_name\") resolving to an out-of-range ordinal after the query changed, or driver-level issues on very wide result sets; it is essentially an assertion that an internal invariant broke.","solutions":["Inspect the index value in the panic message and find the query/row access that produced it — usually a column accessed with an explicit numeric index out of bounds.","Prefer name-based access: `row.try_get::<_, T>(\"column_name\")` instead of positional indices.","Check that the row/query being read matches the SQL executed (schema drift between prepared statement and access code).","If it appears inside sqlx itself with a sane index, file an issue with a reproducer — it indicates a driver bug (index not validated before c_int conversion)."],"exampleFix":"// before\nlet name: String = row.try_get(7usize)?; // index out of range\n\n// after\nlet name: String = row.try_get(\"name\")?;","handlingStrategy":"validation","validationCode":"// Before positional access, bound-check the index against the row:\nif idx >= row.columns().len() {\n    return Err(format!(\"column index {idx} out of range\").into());\n}\nlet val = row.try_get_unchecked::<_, String>(idx)?;","typeGuard":null,"tryCatchPattern":"// Use try_get (returns Result) rather than get, and catch/match the ColumnDecode/IndexOutOfBounds error:\nmatch row.try_get::<_, String>(idx) {\n    Ok(v) => v,\n    Err(sqlx::Error::ColumnNotFound(n)) => fallback_for(n),\n    Err(e) => return Err(e.into()),\n}","preventionTips":["Access columns by name, not positional index","Derive indices from row.columns() lookups instead of hardcoding numbers","Keep query SQL and row-access code in the same module/review scope so schema changes update both"],"tags":["sqlite","panic","index-out-of-range","sqlx"],"backgroundTag":"invalid-column-index","analyzedSha":"03af8bcc5711a1935580a54bea249c219a0c217d","analyzedAt":"2026-09-03T15:01:28.752Z","contentChangedAt":"2026-09-03T15:01:28.752Z","schemaVersion":2},"datasetVersion":"2026-09-10T17:17:09.494Z"}