Command line
Exit codes
Four outcomes, and a precedence order that exists so a scan can never report health it did not observe.
The four codes
| Exit | Name | Meaning |
|---|---|---|
| 0 | everything scanned is healthy | Everything the scan was asked to check is above the threshold. It says nothing about entries it was not given keys for. |
| 1 | observed low TTL | An entry the scan read is at or below the act-now threshold. The boundary is inclusive. |
| 2 | error | Invalid input, an RPC failure, or the network refused. The check did not run. |
| 3 | incomplete | Entry missing, TTL unavailable, executable not followable, or nothing observed. The check ran and could not conclude. |
Read from packages/cli/src/scan.ts’s exported constants; the build refuses if they stop being 0, 1, 2 and 3.
Precedence: 2 > 3 > 1 > 0
When a scan produces more than one outcome, the highest-precedence one wins. Read the order backwards and it explains itself:
- 0 loses to everything. Health is the weakest claim a scan can make, so any other observation displaces it.
- 1 loses to 3. A low reading you took is less important than an entry you could not read at all — the unread one might be lower.
- 3 loses to 2. If the tool itself failed, its partial findings are not trustworthy enough to report as findings.
An incomplete scan is not a healthy one
This is the distinction the codes exist to protect. Exit 3 means the scan ran and declined to conclude; it is not a softer version of exit 0.
A degraded read still exits 3. Blast radius changes severity, not the exit category. And exit status never authorizes a transaction — the code a scan returns has no bearing on what extend will do.
In CI
The GitHub Action surfaces the same code as its exit-code output, so a workflow can distinguish “too close to expiry” from “we could not tell”. Treating 3 as a pass is the most common way to build a check that cannot fail.
Next