Contents
Since October 19, 2026, a workflow with runs-on: ubuntu-latest may start on Ubuntu 26.04 instead of 24.04. GitHub’s changelog says the label moves gradually between October 19 and November 19. It does not say a given repository flips on a given day. Read literally, that is a month in which the same label can resolve to either image, so a job that passed this morning is weak evidence about the job you run this afternoon.
I have not run any workflow on the new image. What follows comes from GitHub’s announcement, the tracking issue, and the image readmes in actions/runner-images, plus one maintainer’s own documentation for setup-ruby.
What changes between the images
The image readmes, as they read on main when I fetched them, differ in the tools most CI scripts touch (kernel and systemd come from the tracking issue):
| Tool | Ubuntu 24.04 | Ubuntu 26.04 |
|---|---|---|
Default Python (python3) | 3.12.3 | 3.14.4 |
| Default Node.js | 22.23.3 | 24.21.0 |
| Docker client and server | 28.0.4 | 29.4.2 |
GCC (apt gcc) | 13.2.0 | 15.2.0 |
| Kernel | 6.17 (Azure) | 7.0 (Azure) |
| systemd | 255.4 | 259.5 |
The versioned toolcache is a softer boundary. Both readmes list the same cached Python (3.10 to 3.14) and both list Node 22 and 24, so actions/setup-python and actions/setup-node with an explicit version should behave the same on either image. Anything that calls the system python3 or node without a setup step gets a different interpreter.
The announcement’s tracking issue lists only the OS, kernel and systemd as changed, and says “Default version remains Java 17.” The 26.04 readme says something else: Java 25.0.4+1 is marked as the default, with 11, 17 and 21 also installed. The 24.04 readme marks 17 as the default. A commenter on the issue noticed the same mismatch, and I found no reply in what I read. If your build relies on JAVA_HOME without a setup-java step, test on ubuntu-26.04 instead of trusting either document.
The issue also does not mention the Docker jump from 28 to 29, which the same commenter flagged. Docker is the kind of change that rarely breaks docker build and sometimes breaks the scripts around it, so it deserves a line in your migration notes either way.
The failure that is already documented
The clearest breakage has a source. The ruby/setup-ruby README says that ubuntu-26.04 “only has builds of CRuby 3.2 and newer, as older CRuby versions do not compile on it.” A workflow with ruby-version: "3.1" on ubuntu-latest therefore works while the label points at 24.04 and fails once it points at 26.04. A comment on the tracking issue reports an Unavailable version 3.4.4 for ruby on ubuntu-26.04 error for a patch release that is too old. The same commenter estimates that 21% of sampled repositories have at least one failing job, but that figure comes from container tests, not hosted runners, so I would not quote it as a measurement.
The pattern generalizes: anything that downloads a prebuilt binary keyed by distribution version, or compiles old code with a newer GCC, fails on the image change and not on any commit you made. The failure arrives with no diff to bisect, and during the rollout it is intermittent.
Why gradual is the part to plan for
If the label flipped atomically, you would see a clean before and after. A gradual rollout produces a harder shape: a matrix job where some legs pass and others fail with no code change, a re-run that goes green, a failure that disappears by itself in November. GitHub’s own wording that migrated workflows “may break builds” is consistent with this, though the announcement does not describe the mechanism that decides which runs move first, and I could not find it in the sources I read.
The practical consequence is that “re-run it” stops being a diagnostic. If a failure involves a toolchain, print the image identity at the start of the job so the failing run records which OS it got:
- run: |
. /etc/os-release
echo "$PRETTY_NAME"
uname -r
That costs one step and turns an intermittent mystery into a log line.
Two ways out
GitHub gives both. To stay on the old image, pin ubuntu-24.04. To test the new one, use ubuntu-26.04, or ubuntu-26.04-arm for Arm. The announcement’s advice is to test before the migration; for most repositories that window has already opened.
My preference is to pin everywhere and migrate on purpose. A floating label in CI is a bet that nothing in your toolchain is sensitive to the OS, and this change shows how that bet gets called. Pin to ubuntu-24.04, add one job on ubuntu-26.04 that is allowed to fail, and promote it when it has been green for a few days. Pinning has a cost: ubuntu-24.04 will not stay current forever, and the announcement does not say how long it will be maintained, so the pin buys time and does not remove the work.
What I could not verify
- How the gradual rollout selects runs or repositories. The changelog gives only the date range.
- Whether the Java default in the readme or the tracking issue is right for the image that actually serves jobs. The readmes were read from
main, which can move. - Arm64 differences. The issue says some software may be available differently there, without detail.
- Anything about behavior on self-hosted runners, which this change does not touch.
Sources
- Ubuntu 26 generally available and latest migration, GitHub changelog, September 17, 2026. Rollout dates, labels, advice.
ubuntu-latestlabel will use Ubuntu 26.04 in November 2026, issue #14748,actions/runner-images. Software table, mitigations, user comments on Ruby, Java and Docker.- Ubuntu 24.04 image readme and Ubuntu 26.04 image readme,
actions/runner-images. Tool versions, read frommain. - ruby/setup-ruby README. The CRuby 3.2 minimum on
ubuntu-26.04. - The Ruby failure rate is a commenter’s estimate from container tests. Nothing here was reproduced on a hosted runner.