PyO3/pyo3 · critical

failed to import `datetime` C API

Error message

failed to import `datetime` C API

What it means

PyO3's `datetime` support caches a pointer to the CPython `PyDateTime_CAPI` structure obtained via `PyDateTime_IMPORT`. `expect_datetime_api` panics if `ensure_datetime_api` returns `Err` — i.e. importing the `datetime` C API failed (typically because the `datetime` module could not be imported). The panic propagates the fetched `PyErr`'s absence as a Rust panic instead of a Python exception.

Source

Thrown at src/types/datetime.rs:50

#[cfg(not(Py_LIMITED_API))]
use core::ffi::c_int;

#[cfg(not(Py_LIMITED_API))]
fn ensure_datetime_api(py: Python<'_>) -> PyResult<&'static PyDateTime_CAPI> {
    if let Some(api) = unsafe { pyo3_ffi::PyDateTimeAPI().as_ref() } {
        Ok(api)
    } else {
        unsafe {
            PyDateTime_IMPORT();
            pyo3_ffi::PyDateTimeAPI().as_ref()
        }
        .ok_or_else(|| PyErr::fetch(py))
    }
}

#[cfg(not(Py_LIMITED_API))]
fn expect_datetime_api(py: Python<'_>) -> &'static PyDateTime_CAPI {
    ensure_datetime_api(py).expect("failed to import `datetime` C API")
}

// Type Check macros
//
// These are bindings around the C API typecheck macros, all of them return
// `1` if True and `0` if False. In all type check macros, the argument (`op`)
// must not be `NULL`. The implementations here all call ensure_datetime_api
// to ensure that the PyDateTimeAPI is initialized before use
//
//
// # Safety
//
// These functions must only be called when the GIL is held!
#[cfg(not(Py_LIMITED_API))]
macro_rules! ffi_fun_with_autoinit {
    ($(#[$outer:meta] unsafe fn $name: ident($arg: ident: *mut PyObject) -> $ret: ty;)*) => {
        $(
            #[$outer]

View on GitHub (pinned to ac9b6899d3)

Solutions

  1. Ensure the Python runtime's stdlib (especially `datetime`) is importable: check `sys.path` and that `datetime.py`/`_datetime` module is included in frozen builds
  2. Add a hidden import of `datetime` in PyInstaller/PyOxidizer configs (`--hidden-import datetime`)
  3. Verify the interpreter is fully initialized before calling datetime APIs (not during `Py_Finalize`)
  4. Use `ensure_datetime_api` directly and handle the returned `PyErr` instead of the panicking helper

Example fix

// PyInstaller spec
// before
# no hidden import, stdlib pruned
// after
hiddenimports=['datetime']
Defensive patterns

Strategy: validation

Validate before calling

# Python: verify datetime C API availability before calling datetime-dependent Rust code
import datetime  # raises ImportError early if stdlib is pruned
assert hasattr(datetime, 'date')

Type guard

def datetime_api_available() -> bool:
    try:
        import datetime
        return True
    except ImportError:
        return False

Try / catch

try:
    result = rust_parse_datetime(value)
except ImportError:
    result = fallback_python_parsing(value)

Prevention

When it happens

Trigger: Extracting to `chrono`/`time` datetime types or constructing `PyDateTime`/`PyDate`/`PyTime`/`PyDelta` objects when the `datetime` module is unavailable; frozen/PyOxidizer/PyInstaller builds missing `datetime`; a broken `sys.path` hiding the stdlib.

Common situations: Frozen binaries (PyInstaller, PyOxidizer, embedded Python) that stripped `datetime`; stub-based or partial Python distributions; calling datetime-related Rust APIs at interpreter shutdown.

Related errors


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