astral-sh/ruff · error
argument index should be valid
Error message
argument index should be valid
What it means
CallArguments::insert_type stores the inferred type for the argument at `index`; the items vector holds one entry per call argument, so the index must have been produced against the same arguments list. The expect is an index-bounds panic: the passed index is >= items.len().
Source
Thrown at crates/ty_python_semantic/src/types/call/arguments.rs:217
pub(crate) fn is_variadic(&self, index: usize) -> bool {
self.items.get(index).is_some_and(|argument| {
matches!(argument.argument, Argument::Variadic | Argument::Keywords)
})
}
pub(crate) fn argument_types(&self, index: usize) -> Option<&CallArgumentTypes<'db>> {
self.items.get(index).map(|item| &item.types)
}
pub(crate) fn insert_type(
&mut self,
index: usize,
tcx: impl Into<TypeContext<'db>>,
ty: Type<'db>,
) {
self.items
.get_mut(index)
.expect("argument index should be valid")
.types
.insert(tcx, ty);
}
pub(crate) fn clear_types(&mut self, index: usize) {
self.items
.get_mut(index)
.expect("argument index should be valid")
.types = CallArgumentTypes::default();
}
pub(crate) fn iter_types(&self) -> impl Iterator<Item = &CallArgumentTypes<'db>> + '_ {
self.items.iter().map(|item| &item.types)
}
/// Returns `true` if the inferred types are equal for the given set of argument indices.
pub(crate) fn inferred_types_equal_at(&self, other: &Self, argument_indices: &[usize]) -> bool {
argument_indices.iter().all(|&index| {View on GitHub (pinned to d1087a4b9e)
Solutions
- Minimize the call expression (defaults/star-args/overloads are common ingredients) and file a ty issue with the backtrace
- As a contributor: derive indices and argument-type writes within the same pass, or use `get_mut` and skip out-of-range indices instead of unwrapping
- Check for nondeterminism by re-running the file several times; intermittent behavior points at iteration-order instability
Example fix
// before
self.items.get_mut(index).expect("argument index should be valid").types.insert(tcx, ty);
// after
if let Some(item) = self.items.get_mut(index) {
item.types.insert(tcx, ty);
} Defensive patterns
Strategy: validation
Validate before calling
debug_assert!(index < arguments.items_len(), "stale argument index");
if index < arguments.items_len() {
arguments.insert_type(index, tcx, ty);
} Prevention
- Keep argument indices and their reads/writes within one inference pass; recompute indices after mutating the arguments list
- Prefer get/get_mut with explicit skip over unwrap for replayed indices
- Re-run a file repeatedly in CI samples to catch intermittent ordering bugs early
When it happens
Trigger: Replaying an argument index captured in an earlier inference pass after the arguments list changed (fixpoint re-inference, mutation between passes), or a mismatch between the number of parameters matched and the number of arguments actually recorded for the call.
Common situations: Nondeterministic inference order across fixpoint iterations; calls mixing defaults, *args/**kwargs, and overloads where the matcher's index arithmetic drifts from the recorded arguments.
Related errors
- argument index should be valid
- bindings must not be empty
- checked bindings are stable across fixpoint iterations
- ParamSpec sub-call should only contain a single CallableBind
- argument index should not be out of range
AI-assisted analysis of astral-sh/ruff@d1087a4b9e (2026-08-20).
Data as JSON: /api/errors/85c37108a96daf74.
Report an issue: GitHub.