PyO3/pyo3 · error

called `append_to_inittab` but a Python interpreter is alrea

Error message

called `append_to_inittab` but a Python interpreter is already running.

What it means

append_to_inittab! must register a module before the interpreter starts, because PyImport_AppendInittab only works pre-initialization. PyO3 checks Py_IsInitialized() and panics if an interpreter is already running.

Source

Thrown at src/macros.rs:220

            wrapped_pymodule::_PYO3_DEF
                .make_module(py)
                .expect("failed to wrap pymodule")
        }
    };
}

/// Add the module to the initialization table in order to make embedded Python code to use it.
/// Module name is the argument.
///
/// Use it before [`Python::initialize`](crate::marker::Python::initialize) and
/// leave feature `auto-initialize` off
#[cfg(not(any(PyPy, GraalPy, all(Py_LIMITED_API, Py_GIL_DISABLED))))]
#[macro_export]
macro_rules! append_to_inittab {
    ($module:ident) => {
        unsafe {
            if $crate::ffi::Py_IsInitialized() != 0 {
                ::core::panic!(
                    "called `append_to_inittab` but a Python interpreter is already running."
                );
            }
            $crate::ffi::PyImport_AppendInittab(
                $module::__PYO3_NAME.as_ptr(),
                ::core::option::Option::Some($module::__pyo3_init),
            );
        }
    };
}

View on GitHub (pinned to ac9b6899d3)

Solutions

  1. Call append_to_inittab! before any interpreter initialization (before Py_Initialize / with_embedded_python_interpreter)
  2. Register all modules in one place at program startup
  3. If the interpreter must already be running, load the module dynamically (PyImport_AddModule + init function) instead of inittab
  4. For embedded multi-phase setups, restructure so module registration happens in the init callback before startup

Example fix

// before
Python::with_embedded_python_interpreter(|py| { ... });
append_to_inittab!(my_module); // panics
// after
append_to_inittab!(my_module);
Python::with_embedded_python_interpreter(|py| { ... });
Defensive patterns

Strategy: validation

Validate before calling

if unsafe { pyo3::ffi::Py_IsInitialized() } == 0 {
    append_to_inittab!(my_module); // safe
} else {
    // use dynamic module loading instead
}

Type guard

fn inittab_registrable() -> bool { unsafe { pyo3::ffi::Py_IsInitialized() } == 0 }

Prevention

When it happens

Trigger: Calling append_to_inittab!(my_module) after Python::with_embedded_python_interpreter / Py_Initialize has already been invoked in the process.

Common situations: Embedding apps that initialize Python in main and later try to register an extension module; registering modules lazily on first use after interpreter startup; re-registering modules on second run within the same process.

Related errors


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