PyO3/pyo3 · error

Converting PyErr arguments failed

Error message

Converting PyErr arguments failed: {}

What it means

PyErr::arguments converts the exception's arguments into a Python object and is documented as infallible, but IntoPyObject can now fail. Since the signature can't return the error, pyo3 panics with the conversion error.

Solutions

  1. Ensure the value passed to new_err has an infallible IntoPyObject impl (or convert to a supported type first, e.g. String)
  2. Provide your own error message instead of relying on arguments conversion
  3. Downcast/manually build the exception with .into_pyobject and handle the Err case yourself

Example fix

// before
PyValueError::new_err(my_custom_obj)
// after
PyValueError::new_err(format!("{}", my_custom_obj))
Defensive patterns

Strategy: validation

Validate before calling

fn args_are_trivially_convertible<T: for<'py> IntoPyObject<'py>>() -> bool { true } // prefer plain str/String/numbers as PyErr args

Prevention

When it happens

Trigger: Creating an exception whose args' IntoPyObject conversion fails (e.g. PyTypeError::new_err(value) where value's IntoPyObject impl returns Err, such as a type that can't be converted in the current interpreter configuration).

Common situations: new_err with a custom type whose IntoPyObject conversion errors at runtime; API evolution where arguments() was fallible-ized but callers kept the old infallible path.

Related errors


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

Appendix: source

Thrown at src/err/mod.rs:69

/// Represents the result of a Python call.
pub type PyResult<T> = Result<T, PyErr>;

/// Helper conversion trait that allows to use custom arguments for lazy exception construction.
pub trait PyErrArguments: Send + Sync {
    /// Arguments for exception
    fn arguments(self, py: Python<'_>) -> Py<PyAny>;
}

impl<T> PyErrArguments for T
where
    T: for<'py> IntoPyObject<'py> + Send + Sync,
{
    fn arguments(self, py: Python<'_>) -> Py<PyAny> {
        // FIXME: `arguments` should become fallible
        match self.into_pyobject(py) {
            Ok(obj) => obj.into_any().unbind(),
            Err(e) => panic!("Converting PyErr arguments failed: {}", e.into()),
        }
    }
}

impl PyErr {
    /// Creates a new PyErr of type `T`.
    ///
    /// `args` can be:
    /// * a tuple: the exception instance will be created using the equivalent to the Python
    ///   expression `T(*tuple)`
    /// * any other value: the exception instance will be created using the equivalent to the Python
    ///   expression `T(value)`
    ///
    /// This exception instance will be initialized lazily. This avoids the need for the Python GIL
    /// to be held, but requires `args` to be `Send` and `Sync`. If `args` is not `Send` or `Sync`,
    /// consider using [`PyErr::from_value`] instead.
    ///
    /// If `T` does not inherit from `BaseException`, then a `TypeError` will be returned.

View on GitHub (pinned to ac9b6899d3)