Short version: ubuntu-latest is moving to Ubuntu 26.04 in percentage stages between 19 October and 19 November 2026, tracked in actions/runner-images#14748. The published change table says the Java default stays at 17, while images/ubuntu/toolsets/toolset-2604.json in the same repository declares "default": "25", and that JSON file is what builds the image. Set runs-on: ubuntu-24.04 to stop the clock, then diff the two toolset files.
One naming point first, because the rest of this depends on it: there are two descriptions of the 26.04 image, and they do not match. The 17 September changelog and announcement issue #14747 carry an eleven-row table of "selected" changes and record "Possible impact: N/A". The image's own Ubuntu2604-Readme.md and toolset-2604.json are generated from the build. Where they disagree, the toolset file wins, and an assistant trained on the announcement will tell you Java 17 held.
This is aimed at whoever owns a repo estate rather than a repo. Six days remain in the window, and the useful question is not whether 26.04 is any good. It is which of your pipelines have already crossed, which release artifacts were compiled against a different JDK, and which of last week's red builds were real. I keep a note on the previous floating-label move, node:lts on 28 October.
12 checks before the label flips on 19 November
- Diff the toolset JSON, not the announcement table. The table lists what GitHub chose to mention. The JSON is the build input, and the diff takes one command.
base=https://raw.githubusercontent.com/actions/runner-images/main/images/ubuntu/toolsets
diff <(curl -s $base/toolset-2404.json | jq -S .) <(curl -s $base/toolset-2604.json | jq -S .)
- Assume the default JDK moved two LTS majors.
toolset-2604.jsondeclares"java": {"default": "25", "versions": ["11", "17", "21", "25"]}, and the 26.04 readme lists 25.0.5+8 as default withJAVA_HOME_25_X64. A barejavacnow emits class file major version 69, which a Java 21 runtime refuses to load, and Java 8 is absent from the image entirely.
java -version 2>&1 | head -1
javap -v -cp build/classes com/acme/Main.class | grep major
- Grep your build files for version-suffixed compiler binaries. The readme lists GNU C++ at 13.4.0, 14.3.0 and 15.2.0, and Clang at 20.1.8, 21.1.8 and 22.1.2 with
default_version: 21.gcc-12,gfortran-12,clang-16andclang-17are gone, so a Makefile carryingCC=gcc-12dies at exec rather than at configure. Cached native addons built on the old image are the second failure behind it: npm rebuild fixes half.
grep -rnE 'gcc-1[0-2]|clang-1[0-9]|gfortran-1[0-2]' --include='*.yml' --include='Makefile*' .
- Four tools vanished that appear in no official list. Mercurial, Julia, Miniconda and Pulumi are missing from the 26.04 readme, and the public acknowledgement sits in issue comments: er0k wrote on 9 November that "It looks Julia has been removed entirely from the ubuntu 26 image", and UserArham added on 11 November that Miniconda went with it. The unpleasant case is the surviving-but-empty
CONDAvariable, which silently turns$CONDA/bin/condainto/bin/conda.
printenv CONDA | wc -c
command -v hg julia conda pulumi || echo "absent on this image"
- Log which image each job ran on, from both the environment and the disk. Hosted runners export
ImageOSandImageVersion, and the image also ships/imagegeneration/imagedata.json. Those two can disagree mid-rollout: #15201 reports the file reading20261025.346.1while the environment variable read20261026.347.1. Action runtimes drift under a fixed label as well: node20 now runs on Node 24.
- run: echo "$ImageOS $ImageVersion"; cat /imagegeneration/imagedata.json
- Run both images for the six days that are left. A two-entry matrix turns a nondeterministic label into two labelled results, which separates a 26.04 regression from an ordinary flake while you can still compare them.
strategy:
matrix:
os: [ubuntu-24.04, ubuntu-26.04]
runs-on: ${{ matrix.os }}
- Read the AppArmor sysctl that flipped between releases.
kernel.apparmor_restrict_unprivileged_unconfinedis 0 on 24.04 and 1 on 26.04. With it on, an unprivileged unconfined process that creates a user namespace runs under a stacked label, and the default container profile then denies signals inside the container. Your container hangs, your tool prints nothing, and the kernel ring buffer holds the only record.
sysctl kernel.apparmor_restrict_unprivileged_unconfined
sudo dmesg | grep 'apparmor="DENIED"'
- Expect enforce-mode profiles to deny file reads your tool never reports. On 11 November rstevens011 reported on #14748 that AppArmor on 26.04 blocks
tsharkfrom loading custom dissector plugins, filed as Launchpad bug 2173933. The workaround posted the following day is a local profile fragment, and it applies to any packaged binary that reads from$HOME.
sudo aa-status | head -3
echo 'owner @{HOME}/** mr,' | sudo tee /etc/apparmor.d/local/tshark
sudo apparmor_parser -r -W /etc/apparmor.d/tshark
- The system interpreter is Python 3.14.4, and the toolcache declares no default.
toolset-2604.jsoncaches 3.11 through 3.15 with nodefaultkey, while the readme reports system Python as 3.14.4. Anything calling barepython3to build a C extension is resolving wheels for a release many projects have not published yet, so pin it withactions/setup-pythonand an exactpython-versioninstead of inheriting whatever the image ships. - Inventory the label across the estate before fixing anything. Code search answers it in one call, with two blind spots worth writing down: it indexes default branches only, and a label buried in a reusable workflow or composite action will not match.
gh api -X GET search/code -f q='"runs-on: ubuntu-latest" org:ACME path:.github/workflows' --jq .total_count
- Pin
ubuntu-24.04, then price the deferral honestly. This row is unverified: neither the 17 September changelog nor #14748 publishes a retirement date for the 24.04 image, and the issue offers only "Switch back to Ubuntu 24.04 by specifying theubuntu-24.04label". The thing that settles it is a subscription to the Announcement label inactions/runner-images, not an assumption that a pin lasts a year. - Confirm the architecture scope before migrating arm64 runners. The changelog describes GA "on both x64 and arm64"; #14748 scopes the label move to "the x64
ubuntu-latestlabel". Read the issue body yourself before you touch an arm workflow, because the opt-in label is probablyubuntu-26.04-arm.
gh api repos/actions/runner-images/issues/14748 --jq .body | grep -i arm
FAQ
Will my ubuntu-latest jobs move without a commit from me? Yes. #14748 describes a percentage-based rollout from 19 October to 19 November 2026, so an unchanged workflow file can run on 24.04 one day and 26.04 the next.
Is Java 17 still available? Yes, as an explicit actions/setup-java version. toolset-2604.json lists 11, 17, 21 and 25 with 25 as the default. Java 8 is not listed.
Can I keep ubuntu-24.04 after 19 November? The label works and the issue names it as the fallback, with no published retirement date for the image. Watch the Announcement label rather than planning around a date nobody has given.
Why did a passing job start failing with no diff? Compare ImageVersion between the two runs before debugging your code. A 2404 to 2604 change means a different compiler set, a different default JDK and AppArmor restriction switched on.
Wrap-up
Probe the image, do not read about it. Every check here resolves to something the runner itself prints, which matters because the published table was accurate on 17 September and has since drifted on Java, Buildx, Rust, Firefox and three cloud CLIs. Pinning is one line per workflow; reconciling an estate, re-establishing which shipped binaries were compiled against JDK 25, and writing the AppArmor profiles a 26.04 fleet needs is scoped work with a real number attached, and 19 November does not move for it. Start with the sweep, commit it on a branch, and watch what goes red:
grep -rln 'runs-on: ubuntu-latest' .github/workflows | xargs sed -i 's/ubuntu-latest/ubuntu-24.04/'
What I read while writing this, in the order it was useful: the GitHub changelog for Ubuntu 26 GA, the migration tracking issue #14748 and its comment thread, the announcement issue #14747 with the eleven-row table, toolset-2604.json, Ubuntu2604-Readme.md, and the image-version mismatch report in #15201.
Comments
Be the first to comment.