You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[Python] Process aborts at interpreter exit: ~PyReadableFile takes the GIL on a ThreadPool worker during finalization (pd.read_parquet on a local path) #54536
Describe the bug, including details regarding any error messages, version, and platform.
A short-lived process that reads a local parquet file through pandas and then exits sometimes aborts with SIGABRT (exit 134), after all of its work and output are done. stderr shows terminate called without an active exception and Fatal Python error: Aborted, with no Python frame.
pandas opens a Python file handle for a local path and passes it to the dataset reader, which wraps it in a PyReadableFile. A reader task can drop the last reference on a ThreadPool worker thread while the interpreter is finalizing. OwnedRefNoGIL::~OwnedRefNoGIL then calls PyGILState_Ensure, CPython ends the thread with pthread_exit, the forced unwind passes a noexcept destructor, and std::terminate is called.
Reproduction
# write.py: run onceimportpandasaspdpd.DataFrame({"a": [1, 2], "b": [1.0, 2.0]}).to_parquet("p.parquet", index=False)
# read.py: run many times, a few in parallelimportpandasaspd, syspd.read_parquet(sys.argv[1], columns=["a", "b"])
print("ok")
Expected: no output (every run exits 0). Observed: 38 134, that is 38 of 3000 runs abort.
The same loop with pyarrow.parquet.read_table(sys.argv[1], columns=["a", "b"]).to_pandas() in place of pd.read_parquet gives no output, so 0 of 3000 runs abort. The file is then opened natively, and no Python object is held by the reader.
Environment
pyarrow 26.0.0 (pyarrow 25.0.1 aborts at the same rate)
Possible fix. Skip the decref in OwnedRefNoGIL's destructor when the interpreter is finalizing (Py_IsFinalizing()), as other C++ extensions do. Alternatively, release the scan's fragments on the calling thread before read_table returns.
Related.ARROW-16597 has the same mechanism in Flight: PyThread_exit_thread → pthread_exit while C++ code is on the stack, at interpreter exit.
Additional reproduction on the current released wheels, run with Codex assistance on the designated remote workstation (Linux x86_64, CPython 3.12.15, PyArrow 26.0.0, pandas 3.0.6):
2 of 300 fresh subprocesses using pandas.read_parquet aborted with signal 6 and terminate called without an active exception.
0 of 300 control subprocesses using pyarrow.parquet.read_table(...).to_pandas() aborted.
This is on x86_64, not the reporter's aarch64 platform, but it reproduces the same exit-time failure on the Python-file-handle path.
I inspected current main (ee382216db4f8d764ed17c16c5baef45afe3f757): PyReadableFile owns the Python file through OwnedRefNoGIL; that destructor checks Py_IsInitialized() and then acquires the GIL before decref. The previously merged #49943 protects PyBuffer and NumPyBuffer, but not this OwnedRefNoGIL path.
I would like to investigate a focused fix and regression test if a committer can assign this issue. Before coding, guidance would help on the supported finalization check across Arrow's Python versions: the remote CPython 3.12.15 headers declare _Py_IsFinalizing, while the issue proposes Py_IsFinalizing.
AI disclosure: Codex assisted with setting up and running the reproduction and inspecting current source. No code changes have been made.
Activity
wpyaoxueros commentedon Oct 20, 2026
Additional reproduction on the current released wheels, run with Codex assistance on the designated remote workstation (Linux x86_64, CPython 3.12.15, PyArrow 26.0.0, pandas 3.0.6):
pandas.read_parquetaborted with signal 6 andterminate called without an active exception.pyarrow.parquet.read_table(...).to_pandas()aborted.This is on x86_64, not the reporter's aarch64 platform, but it reproduces the same exit-time failure on the Python-file-handle path.
I inspected current
main(ee382216db4f8d764ed17c16c5baef45afe3f757):PyReadableFileowns the Python file throughOwnedRefNoGIL; that destructor checksPy_IsInitialized()and then acquires the GIL before decref. The previously merged #49943 protectsPyBufferandNumPyBuffer, but not thisOwnedRefNoGILpath.I would like to investigate a focused fix and regression test if a committer can assign this issue. Before coding, guidance would help on the supported finalization check across Arrow's Python versions: the remote CPython 3.12.15 headers declare
_Py_IsFinalizing, while the issue proposesPy_IsFinalizing.AI disclosure: Codex assisted with setting up and running the reproduction and inspecting current source. No code changes have been made.