Set an explicit timeout-minutes on every job, decide per step whether failure should stop the job, and alert when the automation itself fails. The default job timeout in GitHub Actions is 360 minutes, which is far too long for a notification script.
The defaults
GitHub's workflow syntax reference says the job level timeout-minutes is the maximum number of minutes to let a job run before GitHub cancels it, with a default of 360. A step level timeout-minutes kills the step process after the limit, with a documented maximum of 360, and the value must be a positive integer. There is also continue-on-error, which prevents a job from failing when a step fails.
A hung HTTP call to a ticketing system can therefore sit for six hours, hold a concurrency slot and block the next run. Short limits make hangs visible.
Choose limits by job type
| Job | Suggested job timeout | Reason |
|---|---|---|
| Chat notification | A few minutes | One HTTP call |
| Ticket sync | 10 to 15 minutes | Many small calls |
| Dependency scan | Based on your longest normal run, plus margin | Catch runaway scans |
| Weekly report | 20 to 30 minutes | Gathers data from several sources |
Look at the last twenty successful runs and set the limit at about double the slowest. Revisit when the repository grows.
Which steps may fail quietly
The question to ask per step is: if this fails, is the result still trustworthy?
- Scan step fails: the job must fail. A missing scan must never look like zero findings.
- Report formatting fails: fail, but still try to publish the raw output.
- Chat message fails: often acceptable to continue, since the ticket or summary carries the information. Mark that step
continue-on-errorand log a warning. - Cleanup step fails: continue.
Use continue-on-error sparingly. Each use is a place where failure becomes invisible.
Alert on the automation itself
A failed security job should tell someone. The simplest pattern is a last step with if: failure() that sends a short message to a team channel. Include the workflow name, repository and a run link. Beware of the trap that the alert path may also be broken, so also run a freshness check that asks when the last successful run happened. See detecting a silently failing scheduled scan and monitoring your security gate's health.
Fail open or fail closed
For a release gate, decide in advance what happens when the scanner is down. Failing closed blocks all releases when the vendor has an outage. Failing open lets unscanned code through. Many teams choose fail closed for production branches with a documented, time limited override, and fail open with a loud warning elsewhere. Write the choice down, because the argument is much worse during an outage. Our post on admission webhook timeouts and failure policy discusses the same tradeoff in Kubernetes.
Try it yourself
Click through it at your own pace, or open it full screen.
Watch what the gate does on a failing check and think about what it should do if the scanner itself were unreachable.
Safeguard provides policies and gates for pull requests. Try the free scan at gold.safeguard.sh/scan.
Quick check
What is the default job timeout?
360 minutes according to GitHub's workflow syntax reference. Set a shorter explicit value.
Should a failed scan fail the whole job?
Yes. A scan that did not run must not be reported as a clean result.
Sources
Last reviewed: 19 October 2026.