What a kill looks like
A job that is killed does not fail with a message from your code. The log ends abruptly, often with the single word Killed, an out-of-memory message, or a status of 137 on the step. On Linux, when the kernel cannot find enough memory it starts terminating processes, and the process that dies is not always the one that asked for the memory. A full disk looks different: a message that no space is left on the device, usually in a step that writes files.
Read 137 carefully. It means the process ended because of a signal, and memory is only one reason: Docker's own documentation lists other causes, such as someone killing the container or the daemon restarting. Treat it as a pointer, not a diagnosis.
What the runner actually has
On GitHub's standard Linux runner, a public repository gets 4 virtual CPUs, 16 GB of memory and a 14 GB disk, while a private repository gets 2 CPUs, 8 GB of memory and the same 14 GB disk. The sizes were checked on 11 October 2026 and can change. GitHub describes each hosted runner as a new virtual machine, so leftovers from an earlier job should not be using the disk.
Two consequences follow. The same workflow can pass in a public repository and fail in a private one because the private runner has half the memory. And a job that builds container images, downloads large datasets or keeps several copies of build output can reach 14 GB faster than expected.
Measure before you change anything
Work on a branch. Add a temporary step that records free memory and free disk at the start, between the major steps and at the end, and keep only totals in the log. Run the job and find the step at which the numbers hit the limit. For memory, compare a run with fewer parallel workers: many test and build tools start one worker per core, so the default can multiply the peak. Jest, for example, uses the number of cores minus one by default in a single run, and the option can be lowered for resource-limited CI. Repeat the measurement once, because a single run can be unrepresentative.
For disk, list the largest directories after each heavy step. Typical culprits are build outputs that are never removed, container image layers, caches and downloaded archives.
- Record memory and disk at the same points in each run.
- Change one thing at a time: workers, then step order, then cleanup.
- Keep measurement output free of environment values.
Reduce demand first; buy size last
Fixes that reduce demand: fewer parallel workers, splitting one heavy step into two, deleting large intermediate files as soon as they are no longer needed, a smaller install, and a narrower cache. If the measurements show that the job genuinely needs more than the runner has, a larger runner is the honest answer, and that decision and its cost are yours.
Do not skip tests to save memory, and do not treat a single pass as a margin: the check that matters is how much headroom remains at the peak.
How the paid outcome is accepted
The fixed job covers one job on its current runner size. It is accepted by three consecutive runs that complete with the same tests running, a measured memory and disk margin at the limiting step that is at least the figure you agreed in advance, and a duration inside an agreed bound. It does not include buying or configuring a larger runner. It is £225, untested, paid after you sign off. A job that fails with a normal error is the existing single-job repair.
Sources and limits
- GitHub-hosted runner reference Checked 2026-10-11.
- For the standard Linux runner, public repositories have 4 vCPU, 16 GB RAM and a 14 GB SSD, and private repositories have 2 vCPU, 8 GB RAM and a 14 GB SSD; each hosted runner is a new virtual machine.
- Docker resource constraints Checked 2026-10-11.
- On Linux the kernel starts terminating processes when it cannot find enough memory.
- Docker container listing Checked 2026-10-11.
- A 137 exit status has several causes, including docker kill and a Docker daemon restart, so it does not by itself prove a memory shortage.
- Jest command line options Checked 2026-10-11.
- Jest's default worker count in a single run is the number of available cores minus one, and it can be reduced for resource-limited CI.
- Existing single-job repair Checked 2026-10-11.