PyO3/pyo3 · error

expected error

Error message

expected error

What it means

On CPython 3.14+ (or with the full API), `PyString::from_fmt` formats directly into a `PyUnicodeWriter`. `write_fmt` swallows the real error into the writer, and the code then asserts `take_error()` returns `Some` — if it returns `None` while `write_fmt` failed, the `.expect("expected error")` panics because the writer's internal error state is missing.

Source

Thrown at src/types/string.rs:275

    /// This function is similar to [`format!`], but it returns a Python string object instead of a Rust string.
    #[inline]
    pub fn from_fmt<'py>(
        py: Python<'py>,
        args: fmt::Arguments<'_>,
    ) -> PyResult<Bound<'py, PyString>> {
        if let Some(static_string) = args.as_str() {
            return Ok(PyString::new(py, static_string));
        };

        #[cfg(all(Py_3_14, not(Py_LIMITED_API)))]
        {
            use crate::fmt::PyUnicodeWriter;
            use core::fmt::Write as _;

            let mut writer = PyUnicodeWriter::new(py)?;
            writer
                .write_fmt(args)
                .map_err(|_| writer.take_error().expect("expected error"))?;
            writer.into_py_string()
        }

        #[cfg(any(not(Py_3_14), Py_LIMITED_API))]
        {
            Ok(PyString::new(py, &format!("{args}")))
        }
    }
}

/// Implementation of functionality for [`PyString`].
///
/// These methods are defined for the `Bound<'py, PyString>` smart pointer, so to use method call
/// syntax these methods are separated into a trait, because stable Rust does not yet support
/// `arbitrary_self_types`.
#[doc(alias = "PyString")]
pub trait PyStringMethods<'py>: crate::sealed::Sealed {
    /// Gets the Python string as a Rust UTF-8 string slice.

View on GitHub (pinned to ac9b6899d3)

Solutions

  1. Ensure your types' `Display` impls never return `Err` manually and never panic
  2. Pre-format to a Rust `String` and use `PyString::new` as a fallback
  3. Report a reproducer to pyo3 if it occurs with a plain `format_args!`

Example fix

// before
let s = PyString::from_fmt(py, format_args!("{}", custom))?;
// after
let s = PyString::new(py, &format!("{}", custom));
Defensive patterns

Strategy: fallback

Validate before calling

// ensure Display impls cannot fail; test them
let text = format!("{}", value); // panics-safe pre-check in Rust

Try / catch

// catch the panic and fall back to PyString::new
let s = std::panic::catch_unwind(|| PyString::from_fmt(py, args).unwrap())
    .unwrap_or_else(|_| PyString::new(py, &format!("{}", args_display)));

Prevention

When it happens

Trigger: Calling `PyString::from_fmt(py, args)` where the `format_args!` `Write` implementation fails (e.g. a custom `Display` impl returns an error, or formatting raises into the writer) but the writer does not record an error internally — an internal inconsistency, typically triggered by a `Display` impl that returns `fmt::Error` without the writer capturing a Python error.

Common situations: User `Display` implementations returning `Err(fmt::Error)` manually, panicking/unwinding inside `Display`, or a pyo3 bug where `write_fmt` fails for a non-error reason.

Related errors


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