Skip to content
LatchkeyLatchkey home

macOS runner: "ld: library not found for -lSystem" in CI

The macOS linker resolves -lSystem from the active SDK library directory. When the SDK path is stale or the Command Line Tools are missing, ld cannot find libSystem and the link step fails.

What this error means

A native compile or link (often a Ruby gem, Node native module, or Go cgo build) fails with "ld: library not found for -lSystem" and "clang: error: linker command failed".

ld
ld: library not found for -lSystem
clang: error: linker command failed with exit code 1 (use -v to see invocation)

Diagnose it: is the job queued, or is the runner gone?

A job that never starts and a job whose runner disappeared mid-run look similar in the UI and have opposite causes. The first is a labelling or capacity problem, the second is the runner being killed, usually by memory pressure or a spot reclaim.

.github/workflows/ci.yml
- name: Runner facts
  run: |
    echo "runner name: $RUNNER_NAME"
    echo "os/arch:     $RUNNER_OS/$RUNNER_ARCH"
    nproc; free -h; df -h /
    echo "labels this job asked for: ${{ toJSON(job) }}"

Common causes

The Command Line Tools SDK path is stale

After an OS or Xcode change the active developer directory points at an SDK that no longer holds the system libraries, so -lSystem cannot resolve.

A missing SDKROOT or library search path

The build does not pass the current SDK, so ld searches a path without libSystem.tbd and reports it as not found.

How to fix it

Point the toolchain at the current SDK

  1. Reset xcode-select or select a valid Xcode.
  2. Export SDKROOT to the active SDK so ld searches the right library directory.
  3. Rebuild.
Terminal
sudo xcode-select --reset
export SDKROOT="$(xcrun --show-sdk-path)"
clang main.c -o app

Reinstall Command Line Tools

If the CLT bundle is incomplete, reinstalling restores the SDK and libSystem the linker needs.

Terminal
sudo rm -rf /Library/Developer/CommandLineTools
sudo xcode-select --install

The failures that are not your workflow

  • Exit 137 is the kernel out-of-memory killer, not an application error. Check free -h above against your peak usage.
  • Disk exhaustion presents as unrelated write errors deep in a build. GitHub-hosted runners ship roughly 14 GB of free space, which a Docker-heavy job can exhaust.
  • A lost connection to the server on a self-hosted runner is usually the host being reclaimed or rebooted, not a network fault in your job.
  • A job that starts and immediately fails with no step output normally failed during runner setup, before your workflow ran at all.

How to prevent it

  • Export SDKROOT from xcrun --show-sdk-path for native builds.
  • Select a known-good Xcode version at the start of the job.
  • Verify xcrun --find ld before heavy native compilation.

Frequently asked questions

What causes macOS runner: "ld: library not found for -lSystem" in CI?
There are 2 common causes: the command line tools sdk path is stale and a missing sdkroot or library search path. After an OS or Xcode change the active developer directory points at an SDK that no longer holds the system libraries, so -lSystem cannot resolve.
How do I fix macOS runner: "ld: library not found for -lSystem" in CI?
There are 2 fixes depending on which cause you have: point the toolchain at the current sdk and reinstall command line tools. Work through them in order, since the first is the most common.
What does macOS runner: "ld: library not found for -lSystem" in CI actually mean?
A native compile or link (often a Ruby gem, Node native module, or Go cgo build) fails with "ld: library not found for -lSystem" and "clang: error: linker command failed".
How do I stop macOS runner: "ld: library not found for -lSystem" in CI happening again?
Export SDKROOT from xcrun --show-sdk-path for native builds. The prevention section lists 3 changes that keep it from recurring.

Related guides

References

Not every red build is your code. Latchkey repairs the ones that are not, on the runner. Start free → 30-day trial · No credit card