Can Python be initialized and _PyRuntime.gilstate.tstate_current be null?

I’ve encountered the situation when Python is initialized (Py_IsInitialized() returns 1), but _PyRuntime.gilstate.tstate_current is null.

_PyRuntime.gilstate.tstate_current is then used by _PyInterpreterState_GET() in PyModule_Create2. PyModule_Create2 crashes because _PyInterpreterState_GET() returns an invalid pointer because _PyRuntime.gilstate.tstate_current is null. The pybind11 code crashes during module creation because of this problem.

Debugger shows that _PyRuntime.gilstate.tstate_current was changed to null and back to non-null tens of thousands times before the problem occurs.

Is it a valid condition that Python is initialized and _PyRuntime.gilstate.tstate_current is null ?

Yes, _PyRuntime.gilstate.tstate_current may be NULL when the global interpreter lock is released, such as via PyEval_SaveThread(). However, it’s not valid to call PyModule_Create (or most other Python C APIs for that matter) without holding the global interpreter lock.

The _PyRuntime.gilstate.tstate_current variable was removed in Python 3.12 and replaced by a thread-local variable _Py_tss_tstate, but it’s still the same idea.