
PR Review and CI Are Two Different Systems

GitHub's ubuntu-latest label now resolves to Ubuntu 24.04, removing Python 2, shipping OpenSSL 3, and changing default tool versions across runner images.
If you're running GitHub Actions workflows with runs-on: ubuntu-latest and haven't looked at this recently, your CI environment changed under your feet. GitHub completed the rollout of Ubuntu 24.04 as the image behind ubuntu-latest back in January 2025, and teams that never pinned an explicit version are still discovering breakage months later.
The tricky part isn't that things explode immediately. Some workflows keep passing for weeks before a specific dependency path triggers the difference. And when it does fail, the error message points at your code or a package install, not at the OS swap. That's what makes this worth auditing proactively.
The shift from Ubuntu 22.04 to 24.04 isn't just a kernel bump. GitHub trimmed a significant number of preinstalled tools to stay within their free disk space SLA, and the underlying OS ships newer defaults across the board. Here's what matters most.
Python 2 is no longer on the image at all. The system Python is now 3.12 (up from 3.10 on 22.04), and the older cached versions like 3.7 and 3.8 are no longer available. If any of your scripts, Makefiles, or dependency install steps assume python means Python 2, they'll break. The image does install a python-is-python3 package, so the bare python command exists and points to Python 3. But if your tooling relies on Python 2 semantics or print-statement syntax, that's a hard stop.
Workflows that call pip install against the system Python without actions/setup-python are the ones most likely to hit issues. The 3.12 default also drops some deprecated stdlib modules like distutils, which breaks older setup.py files that import it.
Ubuntu 24.04 ships OpenSSL 3.0.13. This is the change that causes the most confusing errors. Any binary, Ruby gem, or Node native addon compiled against OpenSSL 1.1 will fail to load with errors like symbol lookup error or OPENSSL_1_1_0 not found. OpenSSL 3 also disables some legacy algorithms by default, which can cause TLS handshake failures to older servers.
Ruby native extensions are particularly sensitive here. If you're using a cached gem bundle that was compiled on 22.04, the native .so files will reference OpenSSL 1.1 symbols that no longer exist on the runner.
The default GCC toolchain moved from versions 9-13 on Ubuntu 22.04 to 12-14 on 24.04, with GCC 14 as the new default. GCC 14 is stricter about certain warnings-as-errors, and some C/C++ projects that compiled cleanly on GCC 12 will throw new warnings or outright errors under GCC 14's tightened defaults. Native Node.js addons built with node-gyp are common victims.
The preinstalled Node.js default changed from 18 to 20. Node 16 is still cached but will be replaced by Node 22. If your workflow doesn't use actions/setup-node and relies on whatever node is on PATH, you're now running against Node 20. Most code won't notice, but anything depending on Node 18-specific behavior or deprecated APIs could.
GitHub cut a long list of preinstalled tools to manage image size. Some of the notable removals:
The .NET SDK also dropped versions 6 and 7, keeping only 8+. And Java's default switched from 11 to 17.
Start with a grep. Every workflow using ubuntu-latest without an explicit version pin is affected. Run this from your repo root:
grep -rn 'ubuntu-latest' .github/workflows/For organizations with many repos, use the GitHub API or gh CLI to search across repositories:
gh search code 'ubuntu-latest' --owner your-org --filename '*.yml' --json path,repositoryCheck both runs-on: values and matrix strategy entries. A common pattern is to define os: [ubuntu-latest, windows-latest, macos-latest] in a matrix, which means the Ubuntu leg of your matrix is now on 24.04.
Beyond the workflow YAML, look at what your steps actually do:
apt-get install with pinned package versions. Package versions changed between Jammy (22.04) and Noble (24.04) repos.pip install without actions/setup-python first.After watching the community deal with this for months, a few failure modes come up over and over.
Ubuntu 24.04 marks the system Python as externally managed (PEP 668). Running pip install something directly against the system interpreter gives you an error telling you to use a virtual environment. The GitHub runner image overrides this for now, but upstream tools and containers built on 24.04 won't. Get in the habit of using actions/setup-python or pipx for CLI tools.
Gems with native extensions compiled against the 22.04 image (OpenSSL 1.1, older libffi) won't load on 24.04. The fix is to bust your gem cache when you move to the new runner, or better yet, include the runner OS version in your cache key:
- uses: actions/cache@v4
with:
path: vendor/bundle
key: ${{ runner.os }}-${{ runner.arch }}-gems-${{ hashFiles('Gemfile.lock') }}The runner.os context reports "Linux" for both 22.04 and 24.04, so it won't automatically invalidate your cache. Consider adding the image version from the ImageVersion environment variable, or just manually clear caches during migration.
If your workflow downloads a prebuilt binary (say, a Go or Rust tool compiled elsewhere) that was linked against OpenSSL 1.1, it'll fail with a library-not-found error. You'll need to either use a statically-linked build or one compiled for 24.04.
The 22.04 image cached common Docker base images: alpine, debian, node, moby/buildkit, ubuntu. The 24.04 image caches none of them. If your workflow's first step is a Docker build or run, expect a few extra seconds on every run while base layers are pulled fresh. It's not a failure, but it inflates your build times and might push you past timeout thresholds on tighter setups.
Don't just switch everything to ubuntu-24.04 in one PR and hope for the best. Here's a step-by-step approach that lets you move without surprises.
If you're actively shipping and don't have time to audit right now, pin to ubuntu-22.04 explicitly. This buys you time. GitHub will maintain the 22.04 image for roughly two more years.
jobs:
build:
runs-on: ubuntu-22.04 # pinned while auditingAdd ubuntu-24.04 as a second matrix entry. Let both run in parallel so you can compare results without blocking merges.
strategy:
matrix:
os: [ubuntu-22.04, ubuntu-24.04]
fail-fast: false
runs-on: ${{ matrix.os }}Use fail-fast: false so the 22.04 leg still completes even if 24.04 fails. This gives you a clear diff of what broke.
The act tool lets you run GitHub Actions locally in Docker. You can target specific Ubuntu images to reproduce failures before pushing:
# Run your workflow against the 24.04 image
act -P ubuntu-24.04=ghcr.io/catthehacker/ubuntu:act-24.04 \
-P ubuntu-latest=ghcr.io/catthehacker/ubuntu:act-24.04This maps both ubuntu-latest and ubuntu-24.04 to the community 24.04 image for act. It's not a perfect replica of the GitHub-hosted runner, but it'll catch the vast majority of OS-level breakage: missing tools, OpenSSL mismatches, Python version differences.
Once your 24.04 matrix leg is green, drop the 22.04 leg and switch to ubuntu-24.04 explicitly (not ubuntu-latest). Pinning to a specific version means the next OS bump won't catch you off guard again. You can always add ubuntu-latest as a non-blocking matrix entry to get early warning about future transitions.
Here are the default versions that changed between the two images, pulled from the official runner image readme:
The broader lesson here isn't about Ubuntu 24.04 specifically. It's that ubuntu-latest is a floating target. It's convenient, but it means GitHub decides when your CI environment changes, not you. For personal projects and throwaway workflows, that's fine. For anything where a failed build blocks a deploy or a release, pin your runner version.
You can still benefit from the early-warning system that ubuntu-latest provides by keeping it as a non-required matrix entry. That way you'll see when the next transition is coming without it breaking your merge queue.
The original announcement issue on the runner-images repo has over 1,500 comments and counting, which tells you how many teams this caught off guard. Don't be one of them. Audit your workflows now, pin while you fix, and move to 24.04 on your own schedule.

PR Review and CI Are Two Different Systems

From Provision to Shutdown: The Lifecycle of a Tenki Runner

What Are GitHub Actions Runners? A Complete Beginner’s Guide to CI/CD Workflows
Get Tenki
Change 1 line of YAML for faster runners. Install a GitHub App for AI code reviews. No credit card, no contract. Takes about 2 minutes.