ubuntu-latest-check: finding workflow jobs that break on Ubuntu 26.04

A checker that reads GitHub Actions workflows and lists the ubuntu-latest jobs that will fail on Ubuntu 26.04 because of removed apt packages, missing setup-python builds or old Playwright versions.

The problem

GitHub is moving the ubuntu-latest runner label from Ubuntu 24.04 to Ubuntu 26.04 between 19 October and 19 November 2026. Three kinds of failure can be predicted from the workflow alone: apt packages that 26.04 no longer has (for example gcc-9, gcc-10, clang-14 to clang-16, postgresql-client-16, lzma-dev, libatlas-base-dev), Python versions that actions/setup-python cannot install on 26.04, and Playwright versions without 26.04 support.

The demand is documented:

How it works

ubuntu-latest-check parses the workflow files and expands matrices with GitHub's include and exclude rules, so each finding names the combinations it applies to. For every job on ubuntu-latest it runs three checks:

  1. Every package named in apt-get install or apt install in run: steps, or in awalsh128/cache-apt-pkgs-action, is looked up in the Ubuntu archive indexes of both releases (release, -updates and -security pockets, all four components, including Provides). A package that exists in 24.04 but not in 26.04 is reported.
  2. Requested Python versions are compared with the actions/python-versions manifest. On 26.04 there are no builds for 3.8 and 3.9, and only for patch releases built after 26.04 support was added, so exact pins such as 3.12.3 also fail.
  3. For jobs that run playwright install, the locked Playwright version is read from package-lock.json, pnpm-lock.yaml or yarn.lock. Versions before 1.61.0 fail; 1.61.0 is the first release with ubuntu26.04 entries in its browser registry.

Jobs in a container: or on self-hosted runners are skipped. --repo and --owner scan remote repositories through gh, --label ubuntu-24.04 also checks jobs that were pinned, and the exit code is 1 when there is an error, so the command can run as a CI step.

This is the output for the demo workflow in the repository:

$ ubuntu-latest-check examples/demo
examples/demo/.github/workflows/ci.yml:9: error: job test [os=ubuntu-latest, python-version=3.9]: python 3.9: actions/setup-python has no Python 3.9 build for Ubuntu 26.04 (it has one for 24.04)
examples/demo/.github/workflows/ci.yml:23: error: job test: apt gcc-10: apt package exists in Ubuntu 24.04 but not in 26.04
examples/demo/.github/workflows/ci.yml:23: error: job test: apt postgresql-client-16: apt package exists in Ubuntu 24.04 but not in 26.04
examples/demo/.github/workflows/ci.yml:34: error: job e2e: playwright 1.59.1: Playwright 1.59.1 (from web/package-lock.json) does not support Ubuntu 26.04, 'playwright install' fails there; 1.61.0 is the first release that does
examples/demo/.github/workflows/ci.yml:33: error: job e2e: apt libgdk-pixbuf2.0-0: apt package exists in Ubuntu 24.04 but not in 26.04
examples/demo/.github/workflows/ci.yml:33: error: job e2e: apt libx264-164: apt package exists in Ubuntu 24.04 but not in 26.04
1 workflow files, 2 jobs on ubuntu-latest, 6 errors, 0 warnings (Ubuntu 24.04 -> 26.04)

On the default branches of public repositories on 29 October 2026 it reported, among others, lzma-dev in python/mypy, libatlas-base-dev in numpy/numpy and Playwright 1.58.2 in CieloVistaSoftware/wb-starter. With --label ubuntu-24.04 it reported the Playwright 1.57.0 lock in cncf/maintainer-d that its issue describes.

Testing

The unit tests run against fixed package and version lists. They cover the extraction of apt package names from shell scripts, matrix expansion, the detection of runs-on and container, Python version matching, the three lock file formats, apt sources that turn an error into a warning, skipped jobs and invalid YAML. Two live tests use the real Ubuntu archive and the python-versions manifest: the demo workflow must produce exactly the six findings above, and the repository's own workflow must pass. CI runs all tests on Python 3.9 and 3.13, on every push and once a week.

Limitations

  • Only what is written in the workflow is checked. Packages installed by scripts, Makefiles or through shell variables are not seen.
  • If a job adds an apt source, a missing package is reported as a warning. Whether a PPA builds for 26.04 is not checked.
  • Only x64 is checked.
  • Expressions other than matrix.* references, literal strings and || are not evaluated.
  • Other changes in the 26.04 image (Ruby versions, the default Java version, /tmp as tmpfs, newer compilers) are not checked.
  • Remote scans read only the default branch.

The code and installation instructions are at github.com/Jwrede/ubuntu-latest-check.