GitHub Actions macOS 14 Retirement: Fix Your Builds Before Nov 2
GitHub retires the macOS 14 runner image on November 2, and brownouts are already failing jobs. Here is how to find every macos-14 reference and move without breaking Xcode.
Key takeaways
- GitHub Actions retires the macOS 14 runner image on November 2, 2026, covering macos-14, macos-14-large and macos-14-xlarge.
- Brownouts fail those jobs on October 26, 29 and 30 from 14:00 UTC.
- Move to macos-15 or macos-26, and update any Xcode 15 pins, because Xcode 15 only ships on the macOS 14 image.
On this page
GitHub retires the macOS 14 runner image on November 2, 2026. Jobs on macos-14, macos-14-large, or macos-14-xlarge will stop running. Brownouts already fail them for ten hours at a time, including today, October 26, from 14:00 to 24:00 UTC, then again on October 29 and 30. Switch to macos-15 or macos-26, and check your Xcode version first.
If your iOS or macOS pipeline went red this afternoon with no code change, this is probably why. The rest of this post covers how to find every reference, which label to move to, and the Xcode trap that turns a one-line change into a broken build.
The dates that matter
All times are UTC, from GitHub's retirement notice.
| Date | What happens |
|---|---|
| Oct 26, 14:00 to Oct 27, 00:00 | Brownout: macOS 14 jobs fail |
| Oct 29, 14:00 to Oct 30, 00:00 | Brownout |
| Oct 30, 14:00 to Oct 31, 00:00 | Brownout |
| Nov 2, 2026 | Image retired; macOS 14 labels stop working |
Earlier brownouts ran on October 5, 12, 16, 19, and 23, so some teams have already seen unexplained failures and retried their way past them. GitHub also warns it may reduce macOS 14 capacity before retirement, so expect longer queue times on those labels even outside brownouts.
Find every macos-14 reference
The label hides in more places than runs-on:. Matrix entries, reusable workflow inputs, and composite actions all count.
# In one repo: every workflow line that mentions macos-14
$ grep -rnE "macos-14" .github/
# Across your org (needs gh auth with read access)
$ gh search code "macos-14" --owner your-org --extension yml --limit 100 \
--json repository,path --jq '.[] | "\(.repository.nameWithOwner) \(.path)"'
# Which recent runs actually used it, in one repo
$ gh run list --limit 50 --json name,conclusion,createdAt,url
Two places teams miss. First, matrix.os lists such as os: [ubuntu-latest, macos-14], where the label never appears next to runs-on. Second, reusable workflows that take the runner as an input, so the caller passes macos-14 from a different repository. Search the callers too. Our guide to reusable workflows at org scale covers how those inputs flow.
Pick the replacement label
GitHub recommends four arm64 labels:
macos-15andmacos-15-xlarge: the closest step up, and the safer default for most pipelines.macos-latestandmacos-latest-xlarge: these now point tomacos-26. They will move again in the future without a change on your side.
We pin an explicit version (macos-15 or macos-26) rather than macos-latest. A floating label is exactly how teams end up surprised by an image change like this one. Upgrade on purpose, on your schedule, with a PR you can roll back.
The Xcode trap
This is where the simple label swap breaks builds. Xcode versions are tied to the runner image, per GitHub's runner-images READMEs:
| Image | Installed Xcode | Default |
|---|---|---|
| macOS 14 | 15.0.1 to 15.4, 16.1, 16.2 | 15.4 |
| macOS 15 | 16.0 to 16.4, plus 26.0.1 to 26.3 | 16.4 |
| macOS 26 | 26.0.1 to 26.6 | 26.6 |
Xcode 15 does not exist on macOS 15. If your workflow selects Xcode 15.x explicitly, or silently relies on the macOS 14 default of 15.4, moving to macos-15 changes your compiler. Swift language mode, warnings-as-errors, and deprecated APIs can all surface at once.
Make the version explicit so the change is visible in review:
# .github/workflows/ios.yml
jobs:
build:
runs-on: macos-15
steps:
- uses: actions/checkout@v7
- name: Select Xcode
run: sudo xcode-select -s /Applications/Xcode_16.4.app
- run: xcodebuild -version
- run: xcodebuild -scheme App -destination 'platform=iOS Simulator,name=iPhone 16' build
If you need the smallest possible jump, Xcode_16.2.app exists on both images, so you can pin 16.2 on macos-14 today, get green, then flip the label. That splits one risky change into two boring ones.
Also check simulator destinations. A -destination naming a device or OS runtime that isn't installed on the new image fails at the build step, not the label. The image README lists the installed runtimes.
Cost and capacity notes
Larger runners keep their billing class: macos-14-xlarge maps to macos-15-xlarge or macos-latest-xlarge, both billed as larger runners. macOS minutes are already the most expensive minutes on GitHub Actions, so this is a good moment to check whether every macOS job needs to run on every push; see our breakdown of GitHub Actions pricing. Moving lint, unit tests that don't need a simulator, and packaging to Linux runners can cut the macOS bill substantially.
Questions people ask
When is the GitHub Actions macOS 14 runner retired?
On November 2, 2026. After that, jobs using macos-14, macos-14-large, or macos-14-xlarge won't run. Before retirement, GitHub runs brownouts that temporarily fail those jobs, including October 26, 29, and 30 from 14:00 to 24:00 UTC.
What should I replace macos-14 with?
Use macos-15 for the smallest change, or macos-26 if you want the newest image. macos-latest currently points to macos-26 but will move again. Pin an explicit version, and check your Xcode selection, because Xcode 15 is not installed on the macOS 15 image.
Why did my macOS GitHub Actions job fail with no code change?
Most likely a brownout. GitHub intentionally fails macos-14 jobs during scheduled windows ahead of the November 2 retirement. If the failure lines up with 14:00 to 24:00 UTC on a brownout date, move the job to macos-15 rather than retrying.
The decision, concretely
- Using
macos-14with the default Xcode? Pin Xcode 16.2 onmacos-14first, then switch tomacos-15. - Already on Xcode 16? Change the label to
macos-15today and you're done. - Using
macos-latest? You're already onmacos-26; pin it explicitly. - Org with many repos? Run the
gh search codequery and open one PR per repo before October 29.
The call we'd make
Change the label today, not on November 1. Pin macos-15 and an explicit Xcode version, verify one green build per app, and use the remaining brownouts as free testing rather than outages. The teams that get hurt by image retirements are the ones whose workflows never said which image or which Xcode they depended on.
Sources
More from DevOps
Explore more articles in this category
GitHub Actions Workflow Lockfiles: Pin Every Action, Including the Ones You Can't See
GitHub now records the exact commit of every direct and transitive action in .github/workflows/actions.lock. Here is how to adopt it, what it fixes that SHA pinning never did, and where it still leaks.
PHP2Shell (CVE-2026-109618, CVE-2026-109619): Patch Before the Bots Do
Two unauthenticated RCEs in PHP core, leaked a day before the patch, with exploit attempts already logged. Here is how to tell if you are exposed and what to do tonight.
GitHub Copilot CLI Sandboxing Is GA: What Actually Changed
GitHub made local sandboxing generally available for Copilot CLI on October 7, so the default now restricts the agent instead of trusting it.
You might have missed
Evergreen posts worth revisiting.