Skip to content
Latchkey

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.

.github/workflows/ci.yml
jobs:
  test:
    runs-on: ubuntu-latest
    timeout-minutes: 30      # whole-job cap
    steps:
      - run: ./flaky.sh      # no per-step cap - can run the full 30m

Common 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.

.github/workflows/ci.yml
steps:
  - name: Integration tests
    run: ./integration.sh
    timeout-minutes: 10     # cancels just this step

Layer step and job timeouts

  1. Use step timeouts for individual hang-prone commands.
  2. Keep a job timeout as a safety ceiling for the whole job.
  3. 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.

Related guides

Tired of flaky CI? Latchkey auto-heals failed jobs and retries them for you. Start free →