A non-blocking I/O operation could not complete right now (EAGAIN/EWOULDBLOCK). Most often a subprocess produced output faster than it was drained and a non-blocking pipe filled - or the runner hit a thread/process limit.
What this error means
A program raises BlockingIOError: [Errno 11] Resource temporarily unavailable, frequently while writing to stdout/stderr, draining a subprocess pipe, or spawning threads. It can be intermittent and load-dependent.
Python traceback
BlockingIOError: [Errno 11] Resource temporarily unavailable
File ".../subprocess.py", line ..., in _readerthread
# or on heavy logging to a non-blocking stdout pipe
Common causes
Full non-blocking pipe
A subprocess writes faster than the parent reads, and the pipe is non-blocking, so the write returns EAGAIN instead of blocking. Common when capturing a chatty child’s output by hand.
Thread or process resource limit
Hitting the max threads/processes (ulimit -u) or memory pressure can surface as EAGAIN when creating new OS resources.
How to fix it
Let subprocess drain output for you
Use communicate() (or run(..., capture_output=True)) instead of hand-rolling non-blocking reads from Popen pipes.
Python
out = subprocess.run(cmd, capture_output=True, text=True)
# or for streaming:
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, text=True)
out, _ = proc.communicate()
Raise the process/thread limit
Terminal
ulimit -u 4096 # max user processes/threads
python run.py
How to prevent it
Drain subprocess output with communicate()/run(capture_output=True).
Bound thread/process pools rather than spawning unbounded workers.
When using non-blocking FDs, handle EAGAIN via select/poll instead of treating it as fatal.
Frequently asked questions
What causes ""[Errno 11] Resource temporarily unavailable""?
A subprocess writes faster than the parent reads, and the pipe is non-blocking, so the write returns EAGAIN instead of blocking. Common when capturing a chatty child’s output by hand.
How do I fix "[Errno 11] Resource temporarily unavailable"?
Use communicate() (or run(..., capture_output=True)) instead of hand-rolling non-blocking reads from Popen pipes.
Can Latchkey fix this automatically?
Yes. Latchkey runs your GitHub Actions on managed runners that detect this failure, apply the fix, and retry the job automatically - self-healing is on by default.