Skip to content

macOS release binaries fail to launch: Homebrew liblzma dependency + hardened runtime library validation #163

Description

@HelgeSverre

Summary

Every signed macOS release artifact fails to start:

dyld: Library not loaded: /opt/homebrew/opt/xz/lib/liblzma.5.dylib
  Referenced from: <…>/sema
  Reason: mapping process and mapped file (non-platform) have different Team IDs

Affected: the release tarballs (sema-lang-*-apple-darwin.tar.xz), the generated Homebrew formula (it installs those tarballs), and sema.mcpb (built from them). Hit while installing the v1.36.0 .mcpb into Claude Desktop (~/Library/Logs/Claude/mcp-server-Sema.log).

Root cause

crates/sema/Cargo.toml uses xz2, whose lzma-sys build script prefers a system library:

let want_static = cfg!(feature = "static") || env::var("LZMA_API_STATIC").is_ok();
if !want_static && !msvc && pkg_config::probe_library("liblzma").is_ok() { return; }

On the GitHub macOS runners this finds Homebrew's liblzma, so the binary records an absolute Homebrew path (/opt/homebrew/opt/xz/... on arm64, /usr/local/opt/xz/... on x86_64). Release builds are then signed with a Developer ID and CODESIGN_OPTIONS=runtime (.github/build-setup.yml), which is required for notarization. Hardened runtime enables library validation, and Homebrew bottles are ad-hoc signed with no Team ID, so dyld refuses the dylib.

Two outcomes, both broken: with Homebrew xz installed the launch fails on the Team ID check; without it the launch fails with Library not loaded. The signing configuration is correct; it only surfaces a dependency that must not be in a release binary.

Evidence

  • otool -L on the v1.36.0 arm64 release binary: /opt/homebrew/opt/xz/lib/liblzma.5.dylib; x86_64 slice: /usr/local/opt/xz/lib/liblzma.5.dylib
  • codesign -dvvv binary: flags=0x10000(runtime), TeamIdentifier=9Z2L5FBZS3; dylib: adhoc, no Team ID
  • codesign --force --sign - <binary> (drop hardened runtime, content unchanged) → sema 1.36.0 runs, MCP initialize answers {"serverInfo":{"name":"sema-mcp","version":"1.36.0"}}
  • Same failure from the plain tarball, not only the .mcpb

Version sweep (macOS arm64, otool -L + launch):

Version lzma dep signature runs
v1.33.0 Homebrew ad-hoc (linker-signed) yes (Homebrew xz present)
v1.34.2 Homebrew Developer ID + runtime no — dyld Team ID failure
v1.35.0 Homebrew Developer ID + runtime no — dyld Team ID failure
v1.36.0 Homebrew Developer ID + runtime no — dyld Team ID failure

Signing landed in 8986cd8 (2026-08-02); v1.34.2 is the first successful release that carries it. Pre-signing releases still carry the Homebrew path, so they fail on Macs without Homebrew xz.

Fix

Embed the bundled liblzma:

# crates/sema/Cargo.toml
xz2 = "0.1"
# lzma-sys defaults to pkg-config (Homebrew on macOS runners) → Homebrew dylib
# in the artifact → hardened-runtime library-validation failure. The `static`
# feature builds the bundled liblzma into the binary.
lzma-sys = { version = "0.1", features = ["static"] }

Feature unification applies it to xz2's lzma-sys. Verified in a scratch crate: with the feature the binary has no dynamic liblzma and reports the bundled lzma 5.2.5 (Homebrew's is 5.8.3). LZMA_API_STATIC=1 in the release build env is the narrower alternative.

Guard

Reject release artifacts whose macOS binaries depend on /opt/homebrew or /usr/local dylibs (otool -L). cargo-dist has the equivalent Linux check (#1249) and an open issue about dynamically linked openssl (#290).

Workaround for an installed .mcpb

Re-sign the extracted binary ad-hoc (verified: --version and MCP initialize both work; reverts when the extension is reinstalled):

codesign --force --sign - \
  "$HOME/Library/Application Support/Claude/Claude Extensions/local.mcpb.helge-sverre.sema/server/bin/sema-macos-universal"

Known issue or local misconfiguration

The failure class is known and widely reported: build-machine Homebrew paths leaking into release binaries, then rejected by hardened-runtime library validation (for example dotnet/runtime#131885, Homebrew discussion #6991). The part that is ours is the pipeline configuration that lets lzma-sys pick Homebrew's library over its bundled copy. Signing is not the defect and must stay on for notarization.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions