PyO3/pyo3 · error
0 < N <= 12
Error message
0 < N <= 12
What it means
`array_into_tuple` converts a fixed-size Rust array of `Bound<PyAny>` into a `PyTuple`, asserting `0 < N <= 12` when converting `N` to `Py_ssize_t` for `PyTuple_New`. The bound exists because pyo3's `IntoPyTuple` impls are only generated for arrays of size 1–12; `N == 0` would create a null-item tuple path and larger arrays aren't supported by the trait impls.
Source
Thrown at src/types/tuple.rs:954
// SAFETY: index guaranteed in bounds by the length check
unsafe { t.get_borrowed_item_unchecked($n) }
.extract::<$T>()
.map_err(Into::into)?,
)+))
} else {
Err(wrong_tuple_length(t, $length))
}
}
}
});
fn array_into_tuple<'py, const N: usize>(
py: Python<'py>,
array: [Bound<'py, PyAny>; N],
) -> Bound<'py, PyTuple> {
#[cfg(not(RustPython))]
unsafe {
let ptr = ffi::PyTuple_New(N.try_into().expect("0 < N <= 12"));
let tup = ptr.assume_owned(py).cast_into_unchecked();
for (index, obj) in array.into_iter().enumerate() {
#[cfg(not(any(Py_LIMITED_API, PyPy, GraalPy)))]
ffi::PyTuple_SET_ITEM(ptr, index as ffi::Py_ssize_t, obj.into_ptr());
#[cfg(any(Py_LIMITED_API, PyPy, GraalPy))]
ffi::PyTuple_SetItem(ptr, index as ffi::Py_ssize_t, obj.into_ptr());
}
tup
}
// SAFETY: array is layout compatible with *const *mut crate::PyObject
// and does not steal the bound reference.
#[cfg(RustPython)]
unsafe {
ffi::PyTuple_FromArray(array.as_ptr().cast(), N.try_into().expect("0 < N <= 12"))
.assume_owned(py)
.cast_into_unchecked()
}View on GitHub (pinned to ac9b6899d3)
Solutions
- Use a `Vec<Bound<PyAny>>` or `&[Bound<PyAny>]` instead of a >12-element array
- For empty arrays, use `PyTuple::empty(py)` explicitly
- Ensure the array element type is correct so `try_into` infers N within 1..=12
Example fix
// before: 13-element array let tup = array13.into_pytuple(py); // after let tup = PyTuple::new(py, array13.as_slice())?;
Defensive patterns
Strategy: validation
Validate before calling
const fn array_size_ok<const N: usize>() -> bool { N > 0 && N <= 12 }
// compile-time guard
const _: () = assert!(array_size_ok::<N>()); Type guard
fn convertible_array<const N: usize>(a: [Bound<'_, PyAny>; N]) -> Option<[Bound<'_, PyAny>; N]> {
(1..=12).contains(&N).then_some(a)
} Try / catch
// runtime guard before conversion
let tup = if N == 0 { PyTuple::empty(py) } else { array.into_pytuple(py) }; Prevention
- Keep arrays within 1..=12 elements for IntoPyTuple
- Use Vec/slices for arbitrary lengths
- Use PyTuple::empty for the empty case
When it happens
Trigger: Calling `.into_py_tuple()`/`PyTuple::new` paths on a `[Bound<PyAny>; N]` array with `N == 0` (e.g. `[]` with inferred element type `Bound<PyAny>`) or `N > 12`.
Common situations: Passing an empty array literal to tuple conversion after a `Vec::try_into()`, or upgrading pyo3 code that previously used a Vec and now uses a >12-element array.
Related errors
- out of range integral type conversion attempted on `elements
- failed to convert tuple to list
- Attaching a thread to the interpreter is prohibited while a
- Cannot attach to the Python interpreter while it is finalizi
- Attaching a thread to the interpreter is currently prohibite
AI-assisted analysis of PyO3/pyo3@ac9b6899d3 (2026-09-05).
Data as JSON: /api/errors/95644014ae5d4217.
Report an issue: GitHub.