Introducing Tenki's code reviewer: deep, context-aware reviews that actually find bugs.Try it for Free
Guide on auditing changes when ubuntu-latest updates to Ubuntu 24.04 in CI environments
Hayssem Vazquez-Elsayed
Hayssem Vazquez-ElsayedMar 13, 2026
GitHub ActionsCI/CDUbuntuRunner ImagesDevOps

ubuntu-latest is Ubuntu 24.04: What to Audit


TL;DR

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.

What Actually Changed in the Runner Image

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 Gone, Python 3 Default Jumped

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.

OpenSSL 3.0 Replaces 1.1

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.

GCC/G++ Defaults Jumped to 14

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.

Node.js Default Is Now 20

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.

Removed Tools You Might Be Using

GitHub cut a long list of preinstalled tools to manage image size. Some of the notable removals:

  • Terraform — no longer preinstalled. You'll need to add a setup step.
  • Heroku CLI, Netlify CLI, Vercel CLI — all gone. Install at runtime if you need them.
  • Mono, MSBuild, NuGet — not available for Ubuntu 24 at all currently.
  • R — removed entirely from the image.
  • SVN — gone. Unlikely to affect most teams, but if you have legacy checkout steps, check them.
  • Cached Docker images — the 22.04 image cached common base images (alpine, debian, node, ubuntu). The 24.04 image caches none. Your first docker pull in a workflow will be slower.
  • Cargo audit, clippy, outdated, Bindgen, Cbindgen — removed. Rust workflows that relied on these being preinstalled need explicit install steps.

The .NET SDK also dropped versions 6 and 7, keeping only 8+. And Java's default switched from 11 to 17.

How to Find Affected Workflows

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,repository

Check 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:

  • Any step that runs apt-get install with pinned package versions. Package versions changed between Jammy (22.04) and Noble (24.04) repos.
  • Any step that runs pip install without actions/setup-python first.
  • Any step that compiles native code (node-gyp, Ruby gems with C extensions, CGo builds).
  • Any step that assumes specific tool versions are preinstalled (Terraform, Heroku, etc.).

Common Breakage Patterns

After watching the community deal with this for months, a few failure modes come up over and over.

pip install Breaks on System Python

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.

Ruby Native Extensions Segfault or Fail to Load

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.

OpenSSL-Linked Binaries Refuse to Start

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.

Docker Pull Is Slower

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.

The Safe Migration Path

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.

Step 1: Pin to ubuntu-22.04 Right Now

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 auditing

Step 2: Add a 24.04 Matrix Leg

Add 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.

Step 3: Test Locally with act

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.04

This 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.

Step 4: Fix, Then Switch

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.

Version Comparison Quick Reference

Here are the default versions that changed between the two images, pulled from the official runner image readme:

  • Python: 3.10 (default) → 3.12 (default). Cached 3.7/3.8 dropped.
  • Node.js: 18 (default) → 20 (default). 22 now cached.
  • Ruby: 3.0 (default) → 3.2 (default). 3.3 and 3.4 now cached.
  • Java: 11 (default) → 17 (default).
  • GCC: 9-13 → 12-14 (default 14).
  • Go: 1.21 (default) → 1.23+ (default).
  • OpenSSL: 1.1 → 3.0.13.
  • .NET SDK: 6/7/8 → 8 only.
  • PostgreSQL: 14 → 16.

Stop Using ubuntu-latest for Production Workflows

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.

Related News


Get Tenki

Faster Builds. Smarter Reviews. Start Both For Free.

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.