astral-sh/ruff · error
Should only ever pass a positive integer to `from_nonnegativ
Error message
Should only ever pass a positive integer to `from_nonnegative_i32`
What it means
from_nonnegative_i32 converts a non-negative i32 subscript index to usize for tuple/sequence element lookup; it carries a debug_assert!(index >= 0) and a release-mode expect because any non-negative i32 converts losslessly into a usize of at least 32 bits. The panic means a negative index reached a path that promises non-negative indices (from_negative_i32 exists for the negative case).
Source
Thrown at crates/ty_python_semantic/src/subscript.rs:29
pub(crate) struct OutOfBoundsError;
pub(crate) trait PyIndex<'db> {
type Item: 'db;
fn py_index(
self,
db: &'db dyn Db,
env: &ProgramEnvironment<'db>,
index: i32,
) -> Result<Self::Item, OutOfBoundsError>;
}
fn from_nonnegative_i32(index: i32) -> usize {
static_assertions::const_assert!(usize::BITS >= 32);
debug_assert!(index >= 0);
usize::try_from(index)
.expect("Should only ever pass a positive integer to `from_nonnegative_i32`")
}
fn from_negative_i32(index: i32) -> usize {
static_assertions::const_assert!(usize::BITS >= 32);
index.checked_neg().map(from_nonnegative_i32).unwrap_or({
// 'checked_neg' only fails for i32::MIN. We cannot
// represent -i32::MIN as a i32, but we can represent
// it as a usize, since usize is at least 32 bits.
from_nonnegative_i32(i32::MAX) + 1
})
}
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
enum Position {
BeforeStart,
AtIndex(usize),
AfterEnd,View on GitHub (pinned to d1087a4b9e)
Solutions
- Reduce to a snippet like `t: tuple[int, str]; t[-1]` and file a ty issue with the backtrace
- As a contributor: dispatch on the sign (`if index >= 0 { from_nonnegative_i32 } else { from_negative_i32 }`) before converting
- Workaround: rewrite the negative literal subscript as a non-negative index while the bug is unfixed
Example fix
// before
let idx = from_nonnegative_i32(index);
// after
let idx = if index >= 0 {
from_nonnegative_i32(index)
} else {
from_negative_i32(index)
}; Defensive patterns
Strategy: validation
Validate before calling
// Caller-side sign dispatch before converting an index:
let idx = if index >= 0 { from_nonnegative_i32(index) } else { from_negative_i32(index) }; Prevention
- Always branch on the sign of a subscript index before converting; from_nonnegative_i32 is for the non-negative arm only
- When adding subscript paths, add a test with a negative literal index on a tuple
- In debug builds the debug_assert fires first - never ignore it in local runs
When it happens
Trigger: Subscript inference (e.g., tuple element binding for `t[-1]` or literal string indexing) passing a negative index into from_nonnegative_i32 instead of from_negative_i32 - typically a missing sign check at a call site or a newly added subscript path that forgot the negative branch.
Common situations: Code that indexes tuples or heterogeneous sequences with negative integer literals; refactors of subscript.rs call sites that drop the sign dispatch.
Related errors
- extra use-def data should have been retained
- should be set because `extract_if` only yields elements with
- argument index should be valid
- Expected `NamedTuple` definition to be an assignment
- Expected `NamedTuple` definition r.h.s. to be a call express
AI-assisted analysis of astral-sh/ruff@d1087a4b9e (2026-08-20).
Data as JSON: /api/errors/64a9ea40ac1f4b60.
Report an issue: GitHub.