Exit Codes and Signals in CI/CD: A Practical Guide
Every CI step ends with an exit code. Knowing the common ones turns a cryptic failure into an obvious next step.
A CI job fails when a step returns a non-zero exit code. Most codes fall into a few well-understood buckets: ordinary failures, "command not found", timeouts, and signal-based terminations. Here is what the ones you actually see mean.
Ordinary failures (1, 2)
Exit 1 is the generic "something failed" - almost any tool uses it. Exit 2 often means misuse of a shell builtin, but many tools (make, grep, pytest) also use 2 for their own errors. Neither tells you much on its own; read the logs.
"Command not found" and not executable (127, 126)
Exit 127 means the shell could not find the command - usually a missing tool or a PATH problem. Exit 126 means the file was found but is not executable (wrong permissions or a broken interpreter line).
Timeouts (124)
GNU timeout returns 124 when a command exceeds its time limit. In CI this is frequently a transient hang or a slow network call, though it can also be a genuine deadlock.
Signals (128 + N): 130, 137, 143
A process killed by signal N exits with 128 + N. The common ones: 130 = SIGINT (Ctrl-C / cancellation), 137 = SIGKILL (usually OOM), 143 = SIGTERM (graceful stop, cancellation, or spot-instance preemption).
Key takeaways
- Codes above 128 mean the process was killed by a signal (code − 128 = signal).
- 127 = command not found; 126 = found but not executable.
- 124 = timed out; often transient in CI.
- 137 = SIGKILL (usually OOM); 143 = SIGTERM; 130 = SIGINT.