subprocess.TimeoutExpired
subprocess.TimeoutExpired
Stack trace
Traceback (most recent call last):
File "script.py", line 10, in <module>
result = subprocess.run(['bash', 'long_running_script.sh'], timeout=5)
File "/usr/lib/python3.9/subprocess.py", line 512, in run
raise TimeoutExpired(cmd, timeout)
subprocess.TimeoutExpired: Command '['bash', 'long_running_script.sh']' timed out after 5 seconds Why it happens
When running bash commands from Python using subprocess.run() with a timeout parameter, if the command takes longer than the specified timeout, Python raises subprocess.TimeoutExpired to prevent indefinite blocking. This usually happens if the bash script or command is slow, stuck, or waiting for input.
Detection
Monitor subprocess.run calls with timeout parameters and catch subprocess.TimeoutExpired exceptions to log which commands are timing out and how long they run before timing out.
Causes & fixes
The bash command or script takes longer than the specified timeout to complete.
Increase the timeout value in subprocess.run() to allow the command more time to finish.
The bash command is stuck waiting for input or hanging due to an error.
Modify the bash script to handle inputs properly or fix any infinite loops or blocking calls.
No timeout parameter was set, causing the process to hang indefinitely in some cases.
Always set a reasonable timeout parameter in subprocess.run() to avoid indefinite hangs.
The subprocess is spawning child processes that outlive the timeout, causing cleanup issues.
Use subprocess.Popen with process group management and terminate the entire process group on timeout.
Code: broken vs fixed
import subprocess
# This will raise subprocess.TimeoutExpired if the command runs longer than 5 seconds
result = subprocess.run(['bash', 'long_running_script.sh'], timeout=5)
print(result.stdout) import os
import subprocess
# Use environment variable for timeout and handle TimeoutExpired exception
timeout_seconds = int(os.environ.get('BASH_CMD_TIMEOUT', '10'))
try:
result = subprocess.run(['bash', 'long_running_script.sh'], timeout=timeout_seconds, capture_output=True, text=True)
print(result.stdout)
except subprocess.TimeoutExpired as e:
print(f"Command timed out after {e.timeout} seconds")
# Optionally handle cleanup or retries here Workaround
Wrap the subprocess.run call in a try/except block catching subprocess.TimeoutExpired, then kill the process manually or log the timeout and continue without crashing.
Prevention
Design bash scripts to complete promptly or support non-blocking operation, always set timeouts in subprocess calls, and implement robust exception handling to avoid unhandled timeouts.