---
title: Pass Explicit check= to subprocess.run
impact: HIGH
impactDescription: subprocess.run silently ignores non-zero exit codes by default; a failed command goes undetected and subsequent code runs on corrupt or missing output.
tags: python, subprocess, error-handling, quality, security
---

## Pass Explicit check= to subprocess.run

`subprocess.run()` has `check=False` by default, meaning a command that exits with a non-zero status (indicating failure) does not raise an exception. Code that follows assumes success and may operate on missing or corrupt output without any error ever being raised.

Always pass `check=True` unless you explicitly intend to handle failures yourself by inspecting `returncode`.

**Incorrect:**
```python
import subprocess

# Exit code ignored — if ffmpeg fails, output file doesn't exist
subprocess.run(["ffmpeg", "-i", "input.mp4", "output.mp4"])

# result.returncode is never checked
result = subprocess.run(["git", "pull"])
print("Done")  # runs even if git pull failed

# capture_output=True but still no check
result = subprocess.run(
    ["python", "migrate.py"],
    capture_output=True,
    text=True,
)
apply_migrations()  # runs even if migrate.py failed
```

**Correct:**
```python
import subprocess

# Raises CalledProcessError if command fails
subprocess.run(
    ["ffmpeg", "-i", "input.mp4", "output.mp4"],
    check=True,
)

# Or capture output and check explicitly
result = subprocess.run(
    ["python", "migrate.py"],
    capture_output=True,
    text=True,
    check=True,                  # raises on non-zero exit code
)
apply_migrations()  # only reached if migration succeeded

# When you WANT to handle failures yourself — explicit intent:
result = subprocess.run(["git", "pull"], check=False)
if result.returncode != 0:
    logger.warning("git pull failed with code %d", result.returncode)
```

**Tools:** Ruff `PLW1510` (subprocess-run-without-check), Pylint `W1510`, Bandit `S603`, flake8-bugbear
