Skip to main content
Builder’s Journal

Why Your Xcode 26 Build Hangs Forever With No Output (and How to Build Anyway)

· · 5 min read

The short answer

Xcode 26 splits the Metal toolchain into a separate downloadable component. When it is missing, an internal coordinator deadlocks during xcodebuild initialisation, before any target work, so every build hangs with no output and no error. The documented fix, xcodebuild -downloadComponent MetalToolchain, hangs in the same place. For a command-line or framework target, skip xcodebuild and compile with swiftc.

The symptom

I kicked off a Swift build with xcodebuild and got nothing back. No compiler output, no progress, no error, no timeout. The process simply sat there. I killed it and retried, and the retry behaved identically. There was nothing to read, nothing to grep for, and nothing in the output to suggest what it was waiting on. A build that normally finishes in seconds had become an open-ended hang.

The environment

I build a Swift project on a headless Mac mini with no monitor attached, driven remotely over SSH from another machine. That detail matters more than it looks, because a hang with no output on a headless box is completely invisible: there is no window, no beachball, and no dialog you can see. Everything you know about the build has to come from the command line.

What I first suspected

My first instinct was the usual first-launch housekeeping that a fresh Xcode wants after an upgrade. So I ran the standard incantation:

sudo xcodebuild -runFirstLaunch

That did install missing first-launch components, and it completed cleanly, so it looked promising. But the build still hung in exactly the same way. Whatever was wrong, it was not the ordinary post-upgrade setup.

How I diagnosed it

The problem with a deadlock is that it never errors, so there is no message to search for. The tool that cracked it is one most developers never reach for: macOS’s sample, which snapshots what a running or hung process is actually doing right now.

sample <pid>

I pointed it at the wedged xcodebuild process. The stack came back parked in IDEMetalToolchainCoordinator.ioQueue, inside IDEDownloadableMetalToolchainCoordinator.gatherInputsAndComputeVersionMatchingRules(). That single stack trace turned an invisible hang into a named cause. The build was not compiling anything. It was stuck trying to work out the Metal toolchain before it did any real work.

The verified root cause

Xcode 26 ships the Metal toolchain as a separate downloadable component. When that component is missing, the coordinator responsible for it deadlocks during initialisation rather than returning an error. Because this happens during xcodebuild initialisation, before any target-specific work begins, it blocks every build. It does not matter whether your project contains a single Metal shader. Mine did not need Metal at all, and it still hung, because the deadlock happens upstream of anything project-specific.

To show how bad a silent deadlock can get: on the same machine an earlier xcodebuild had been wedged in this exact state for 19 days, quietly blocking every build the whole time. I confirmed the elapsed time with:

ps -eo etime

There was also a stale SecurityAgent GUI authentication prompt sitting invisibly on the headless machine, waiting for a click that could never come because there was no screen to click on.

When the official fix is itself broken

The documented remedy for a missing component is to download it explicitly:

xcodebuild -downloadComponent MetalToolchain

It hung in the identical stack. Worse, it never opened a single network connection, so the supposed “download” was doing nothing at all. I proved that with:

lsof -p <pid>

Zero network sockets during what was meant to be a download. The official fix is blocked by the very deadlock it is supposed to resolve, so it cannot help you here.

The fix that worked

The insight that got me building again is that a command-line tool or framework target does not need xcodebuild at all. Compiling directly with swiftc bypasses the entire IDE coordinator layer, including the Metal toolchain coordinator that was deadlocking. The invocation I used, with the frameworks the tool links, was:

swiftc -O -o out src/*.swift -framework CoreML -framework Vision

It built in seconds. No coordinator, no toolchain check, no hang. Killing the stale wedged processes first was necessary, but on its own it was not sufficient, because a fresh xcodebuild would simply deadlock again. Dropping xcodebuild for this target was what actually unblocked the work.

Two reusable lessons

Beyond this specific bug, two things are worth keeping.

  • Diagnose any silent hang on macOS with sample <pid>. Most developers never touch it, yet it turns an invisible hang into a named cause by showing you exactly where the process is parked. When there is no error to search for, the stack is the evidence.
  • For non-app targets, you can drop xcodebuild entirely and compile with swiftc. It is far faster and immune to IDE-layer breakage. If you run Xcode headless, in CI, or over SSH, both of these are worth having in your back pocket.

When this may not apply

A full app target that needs bundling, asset catalogs, and code-signing still needs xcodebuild. The swiftc bypass is for command-line and framework targets, not for producing a signed app bundle. And if your project genuinely uses Metal, you will need the toolchain eventually. The point is not that Metal is optional. The point is that a missing toolchain should not silently deadlock every unrelated build.

A reusable checklist

  1. Build hangs with no output and no error? Do not keep retrying. Find the pid.
  2. Run sample <pid> and read the stack. If it mentions IDEMetalToolchainCoordinator, you are hitting this deadlock.
  3. Check how long it has been stuck with ps -eo etime, and look for stale wedged builds you did not know about.
  4. On a headless machine, watch for an invisible SecurityAgent prompt with no screen to accept it.
  5. Do not rely on xcodebuild -downloadComponent MetalToolchain here. Confirm whether it is actually downloading with lsof -p <pid>; if there are no network sockets, it is deadlocked too.
  6. For a command-line or framework target, kill the stale processes and build with swiftc, linking the frameworks your tool needs.

Takeaway

A missing downloadable toolchain turned into a silent, multi-day deadlock, and sample plus swiftc got me building in seconds while the official fix stayed stuck.

AI assisted with drafting this article. The diagnosis, commands, and stack traces are from my real machine.

Share this article