GitHub Actions Per-Step timeout-minutes Not Cancelling a Hung Step
A hung step runs far longer than expected because timeout-minutes was placed at the wrong level. A job-level timeout-minutes caps the whole job; a step-level one must be set on the individual step to cancel just that step.
What this error means
A single command hangs for the full job timeout (or the 6-hour ceiling) instead of being cancelled quickly, because no step-level timeout-minutes applied to it.
jobs:
test:
runs-on: ubuntu-latest
timeout-minutes: 30 # whole-job cap
steps:
- run: ./flaky.sh # no per-step cap - can run the full 30mCommon causes
timeout-minutes at the job, not the step
A job-level timeout-minutes only cancels the entire job after the limit. To bound a single step, set timeout-minutes on that step.
No timeout at all on a hang-prone step
Without any timeout, a step blocked on a lock, prompt, or dead network waits until the job ceiling, wasting minutes.
How to fix it
Set timeout-minutes on the step
Add a tight per-step timeout so a hang fails that step in minutes.
steps:
- name: Integration tests
run: ./integration.sh
timeout-minutes: 10 # cancels just this stepLayer step and job timeouts
- Use step timeouts for individual hang-prone commands.
- Keep a job timeout as a safety ceiling for the whole job.
- Add non-interactive flags so steps do not block on input.
How to prevent it
- Put timeout-minutes on hang-prone steps, not only on the job.
- Keep a job-level timeout as an overall ceiling.
- Run commands non-interactively so they never wait on a prompt.