PyO3/pyo3 · error

out of range integral type conversion attempted on `elements

Error message

out of range integral type conversion attempted on `elements.len()`

What it means

`PyTuple::new` (via `try_new_from_iter`) converts the input iterator's `ExactSizeIterator::len()` into C's `Py_ssize_t`; if the length exceeds `Py_ssize_t::MAX` the `try_into()` fails and this expect panics. PyO3 checks this itself because `PyTuple_New`'s overflow error is unhelpful.

Source

Thrown at src/types/tuple.rs:44

use core::iter::FusedIterator;
#[cfg(feature = "nightly")]
use core::num::NonZero;

#[cfg(all(not(any(PyPy, GraalPy)), any(not(Py_LIMITED_API), Py_3_12)))]
use libc::size_t;

#[inline]
#[track_caller]
#[cfg_attr(RustPython, allow(unused_mut))]
fn try_new_from_iter<'py>(
    py: Python<'py>,
    mut elements: impl ExactSizeIterator<Item = PyResult<Bound<'py, PyAny>>>,
) -> PyResult<Bound<'py, PyTuple>> {
    // PyTuple_New checks for overflow but has a bad error message, so we check ourselves
    let len: Py_ssize_t = elements
        .len()
        .try_into()
        .expect("out of range integral type conversion attempted on `elements.len()`");

    #[cfg(not(RustPython))]
    let (tup, counter) = unsafe {
        let ptr = ffi::PyTuple_New(len);

        // - Panics if the ptr is null
        // - Cleans up the tuple if `convert` or the asserts panic
        let tup = ptr.assume_owned(py).cast_into_unchecked();

        let mut counter: Py_ssize_t = 0;

        for obj in (&mut elements).take(len as usize) {
            #[cfg(not(any(Py_LIMITED_API, PyPy, GraalPy)))]
            ffi::PyTuple_SET_ITEM(ptr, counter, obj?.into_ptr());
            #[cfg(any(Py_LIMITED_API, PyPy, GraalPy))]
            ffi::PyTuple_SetItem(ptr, counter, obj?.into_ptr());
            counter += 1;
        }

View on GitHub (pinned to ac9b6899d3)

Solutions

  1. Chunk or reduce the collection before building the tuple
  2. Fix the custom iterator's `len()`/`size_hint` implementation
  3. Build incrementally with a `PyTupleBuilder`-style approach or return a `PyResult` error instead

Example fix

// before
let tup = PyTuple::new(py, huge_iter)?;
// after
let items: Vec<_> = huge_iter.take(1_000_000).collect();
let tup = PyTuple::new(py, items)?;
Defensive patterns

Strategy: validation

Validate before calling

fn tuple_len_safe<T>(items: impl ExactSizeIterator<Item = T>) -> bool {
    items.len() <= isize::MAX as usize
}

Try / catch

let result = std::panic::catch_unwind(|| PyTuple::new(py, items.clone()));

Prevention

When it happens

Trigger: Calling `PyTuple::new(py, iterable)` where the iterator's `len()` exceeds `Py_ssize_t::MAX` — an enormous collection on 32-bit targets, or a custom `ExactSizeIterator` whose `len()` lies.

Common situations: wasm32/i686 builds handling huge generated collections; bespoke iterators returning bogus lengths from `size_hint`/`len`.

Related errors


AI-assisted analysis of PyO3/pyo3@ac9b6899d3 (2026-09-05). Data as JSON: /api/errors/879471aa64a9e1a6. Report an issue: GitHub.