Analysis
ubuntu-latest Is Moving to 26.04: GitHub Actions and Azure Pipelines
GitHub Actions now offers Ubuntu 26.04 runners for x64 and arm64. More importantly, ubuntu-latest will move from 24.04 to 26.04 during a phased migration from October 19 through November 19, 2026.

If you arrived here after seeing the runner warning about October 19, it is advance notice of that image migration, not by itself a failed build. GitHub tracks the rollout in runner-images issue #14748. Check the failed step separately if your job is already red.
Using Azure Pipelines? Use the Azure pool setting below; runs-on is GitHub Actions syntax.
In this article
Keep the current Ubuntu release while you test
In the affected job under .github/workflows/, replace:
runs-on: ubuntu-latest
with:
runs-on: ubuntu-24.04
This keeps that job on the Ubuntu 24.04 image family. It does not freeze the image’s installed packages at today’s versions. Check reusable workflows and matrix definitions too: changing one visible runs-on line may not cover all the jobs using the moving label.
If you already have a green 26.04 compatibility run, choose ubuntu-26.04 explicitly instead. Keep architecture unchanged during the comparison; the arm64 label is ubuntu-26.04-arm, not an interchangeable spelling of the x64 runner.
Seeing “Remote machine provider issue” in Azure Pipelines?
The migration announcement lists Azure DevOps as well as GitHub Actions. If the warning appears in an Azure Pipeline, do not paste the GitHub runs-on examples into that pipeline. For a Microsoft-hosted Ubuntu job, the equivalent pin is:
pool:
vmImage: 'ubuntu-24.04'
Edit the existing pool definition in your pipeline YAML or its template; do not add a duplicate key. Azure permits this setting at pipeline, stage, or job level, and the most specific definition wins. A job-level override can therefore defeat a change made only at the top of the file. The pool schema documents that precedence.
Use ubuntu-26.04 for a separate compatibility run when ready. Microsoft lists both releases in its hosted-agent image table. This setting is for Microsoft-hosted agents; do not replace a named self-hosted pool with it. Like the GitHub label, it selects an image family rather than freezing every package version.
The diagnostic step and matrix below use GitHub Actions syntax. The comparison advice applies to both services, but their YAML is not interchangeable.
The runner image is part of the build input
A CI job depends on the kernel, system libraries, compiler defaults, preinstalled tools, package repositories, certificates, locale, and architecture. A lockfile does not pin those layers. A project can have deterministic application dependencies and still change because the image changed underneath them.
GitHub publishes image software lists and notes tools that were added, upgraded, or removed. Compare those lists with what the workflow actually invokes. Pay particular attention to commands used without an explicit setup action, native modules, browser tests, container tooling, and scripts that parse operating-system output.
Test both labels before the migration
Add ubuntu-26.04 to a temporary matrix while retaining ubuntu-24.04. Do not make every duplicate job required immediately; first use it to identify differences. When the results converge, decide whether the repository values stability or automatic upgrades.
Pinning 24.04 is appropriate when a release process cannot absorb an unplanned base-image change. Staying on ubuntu-latest is appropriate when regular migration is intentional and the team maintains the job. Neither label eliminates maintenance.
Record which image produced the failure
Add this step before the setup or build step that is failing. It prints selected version information, not the entire environment, which can contain credentials:
- name: Record runner image
shell: bash
run: |
cat /etc/os-release
uname -m
printf 'ImageOS=%s\n' "${ImageOS:-unknown}"
printf 'ImageVersion=%s\n' "${ImageVersion:-unknown}"
for tool in git node python3 gcc docker; do
if command -v "$tool" >/dev/null 2>&1; then
if "$tool" --version; then
:
else
status=$?
printf '%s: version check failed (exit %s)\n' "$tool" "$status"
fi
else
printf '%s: not installed\n' "$tool"
fi
done
A failed version command is reported without stopping the remaining diagnostic commands. This does not make a failed build pass: keep the setup, build, and test steps separate and retain their failure handling.
Adjust the tool list to the project. An absent compiler matters to a native build; it may be irrelevant to a job that only checks Markdown. Preserve the log from both runner versions alongside the first failing step.
Compare the same test job on both images
For an existing test-only job, the runner selection can use this matrix configuration:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-24.04, ubuntu-26.04]
This is a job fragment, not a complete workflow. Keep the checkout, dependency setup, and test steps from your existing job. If it already has a matrix, merge the operating-system axis into it instead of replacing its language-version or architecture coverage.
fail-fast: false lets the other matrix job finish after one fails. It does not make failures successful. Keep experimental checks separate from release gates until you have reviewed the results and any required-check names.
Do not duplicate a job that publishes packages, pushes images, deploys, or runs migrations against shared infrastructure. Two matrix entries mean two executions. Separate those side effects from the compatibility test, and check runner-minute usage before applying the change across many repositories.
| Result | Next step |
|---|---|
| 24.04 passes; 26.04 fails | Compare the first failing step and its dependencies. Keep 24.04 for releases while investigating. |
| Both fail at the same step | Check shared inputs first: the commit, dependency resolution, credentials, or an external service. |
| Both pass | Check that both ran the same tests and exercised any native builds. Then choose a runner label. |
| 26.04 passes only with an old cache | Repeat with a fresh compatibility-test cache key before concluding that clean builds work. |
Phased rollout can make failures look intermittent
During the October-to-November migration, jobs may land on different image generations as GitHub changes the label behind the service. Record /etc/os-release and relevant tool versions in diagnostic output so a failure can be tied to the runner that produced it.
Self-hosted runners are not automatically protected. Their risk is the reverse: an image can remain stale for years while workflow authors assume GitHub maintains it. The correct control is an explicit lifecycle, whether the runner is hosted or self-hosted.
I would test the release job before October 19, using the same commit on both images and excluding publishing or deployment steps. If 26.04 fails, pin the release job to 24.04 while investigating. A passing comparison is a reason to migrate; the warning alone is not a reason to stop shipping.
Source
GitHub: Ubuntu 26.04 availability and latest-label migration.