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

`PyList::new` computes the collection's `size_hint()` lower bound and converts it to C's `Py_ssize_t`; on platforms where `usize` cannot fit into `Py_ssize_t` (e.g. 32-bit targets with collections > ~2^31 elements) the `try_into()` fails and this expect panics. PyO3 performs the check itself because CPython's `PyList_New` overflow error message is poor.

Source

Thrown at src/types/list.rs:100

    ///
    /// This function will panic if `element`'s [`Iterator::size_hint`] implementation is incorrect.
    /// All standard library structures implement this trait correctly, if they do, so calling this
    /// function with (for example) [`Vec`]`<T>` or `&[T]` will always succeed.
    #[track_caller]
    pub fn new<'py, T>(
        py: Python<'py>,
        elements: impl IntoIterator<Item = T>,
    ) -> PyResult<Bound<'py, PyList>>
    where
        T: IntoPyObject<'py>,
    {
        let mut elements = elements.into_iter().map(|e| e.into_bound_py_any(py));
        let (min_len, _) = elements.size_hint();

        // PyList_New checks for overflow but has a bad error message, so we check ourselves
        let len: Py_ssize_t = min_len
            .try_into()
            .expect("out of range integral type conversion attempted on `elements.len()`");

        let list = unsafe { ffi::PyList_New(len).assume_owned(py).cast_into_unchecked() };

        let count = (&mut elements)
            .take(len as usize)
            .try_fold(0, |count, item| unsafe {
                #[cfg(not(Py_LIMITED_API))]
                ffi::PyList_SET_ITEM(list.as_ptr(), count, item?.into_ptr());
                #[cfg(Py_LIMITED_API)]
                ffi::PyList_SetItem(list.as_ptr(), count, item?.into_ptr());
                Ok::<_, PyErr>(count + 1)
            })?;

        assert_eq!(len, count, "Attempted to create PyList but `elements` was smaller than reported by its `size_hint` implementation.");

        elements.try_for_each(|item| list.append(item?))?;

        Ok(list)

View on GitHub (pinned to ac9b6899d3)

Solutions

  1. Reduce the collection size or chunk the input before constructing the list
  2. Fix the custom iterator's `size_hint` if it reports an incorrect length
  3. Use a fallback construction (e.g. `PyList::empty` + `append` in a loop) for unbounded inputs

Example fix

// before
let list = PyList::new(py, huge_iter)?;
// after
let list = PyList::empty(py);
for item in huge_iter.take(1_000_000) { list.append(item)?; }
Defensive patterns

Strategy: validation

Validate before calling

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

Try / catch

// catch_unwind around list construction if input size is untrusted
let result = std::panic::catch_unwind(|| PyList::new(py, items.clone()));

Prevention

When it happens

Trigger: Calling `PyList::new(py, iterable)` where the iterable's `size_hint().0` exceeds `Py_ssize_t::MAX` — only feasible with a custom `ExactSizeIterator` lying about its length or an enormous collection on a 32-bit platform.

Common situations: 32-bit builds (wasm32/i686) processing very large generated collections, or a custom iterator whose `size_hint` returns a bogus huge lower bound.

Related errors


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