Python "BrokenProcessPool" with concurrent.futures in CI
A worker in a ProcessPoolExecutor exited without returning a result - killed by the OOM reaper, a segfault, or an uncaught fatal signal. The executor cannot recover and marks the whole pool broken.
What this error means
A parallel step fails with "concurrent.futures.process.BrokenProcessPool: A process in the process pool was terminated abruptly while the future was running or pending." It is often intermittent under memory pressure.
concurrent.futures.process.BrokenProcessPool: A process in the process
pool was terminated abruptly while the future was running or pending.Common causes
A worker was OOM-killed
Each worker holds its own copy of large data; collectively they exceed runner memory and the kernel kills one, breaking the pool.
A native crash inside a worker
A C-extension segfault or an uncaught fatal signal terminates a worker process without a Python-level exception.
How to fix it
Reduce memory pressure or worker count
- Lower
max_workersso total memory stays within the runner. - Chunk inputs so each task holds less data at once.
- Re-run and watch peak memory.
from concurrent.futures import ProcessPoolExecutor
with ProcessPoolExecutor(max_workers=2) as ex: # was os.cpu_count()
results = list(ex.map(work, chunks))Isolate the crashing task
Run the suspect task in-process to surface the real exception or segfault the pool was hiding.
# run one task directly to see the underlying crash
work(chunks[0])How to prevent it
- Size
max_workersto the runner memory, not just CPU count. - Chunk large inputs so per-worker memory stays bounded.
- Guard native extension calls that can crash workers.