~/fix/"Xcode failed to verify code signature" — fix
2026·04·20
fix20 April 2026#app-development

"Xcode failed to verify code signature" — fix

Why Xcode refuses to launch an app on device with "failed to verify code signature" and the four root causes ranked by frequency, with a fix for each.

TL;DRThe app on disk doesn't match the signature it was installed with — usually because something modified the bundle after signing (a script, an entitlements injector, or `lldb` attaching). Re-build with all post-sign mutators disabled, or re-sign as the very last step of the build.
Failed to verify code signature of <App.app>.

What 'verify code signature' means here

After Xcode signs the `.app`, the signature is a Merkle-tree hash of every file inside the bundle, sealed with your certificate. Before launching the app on device, `installd` re-hashes the bundle and compares. If a single byte changed, it fails — there is no partial trust.

Root cause ranked by frequency

  1. A Run Script Phase modifies files inside the `.app` after the Sign phase. (~50% of cases.)
  2. An entitlements / Info.plist injection tool runs after signing.
  3. A SwiftPM or CocoaPods plugin writes a new resource on first launch.
  4. Free disk space ran out mid-copy and the bundle is genuinely corrupt.

Fix path A — Run Script Phase order

Open the app target → Build Phases. The order matters. The phase named `[CP] Embed Pods Frameworks` (CocoaPods) or `Sign Embedded Frameworks` must be after every script that touches files in `${BUILT_PRODUCTS_DIR}/${WRAPPER_NAME}/`. Drag any custom script that writes into the bundle to be above the signing phase.

Common offenders: scripts that copy a per-environment `GoogleService-Info.plist`, write a build-time `Info.plist` value, or inject a Sentry / Datadog symbol upload manifest.

Fix path B — re-sign at the end

If you can't re-order (e.g. the script depends on signed binaries existing), add a final re-sign phase:

/usr/bin/codesign --force --sign "$EXPANDED_CODE_SIGN_IDENTITY" \
  --entitlements "$BUILT_PRODUCTS_DIR/$TARGET_NAME.app.xcent" \
  --timestamp=none \
  "$BUILT_PRODUCTS_DIR/$WRAPPER_NAME"

This re-seals the bundle with whatever signature Xcode would have used. Add it as the very last build phase.

Fix path C — first-launch resource writes

Some libraries (notably older versions of Realm, Hermes, and certain DRM SDKs) write a cache file inside the bundle on first run. On simulator or local development this works; on device with a stricter `installd`, it fails verification before the app even gets to run. Move those writes to `~/Documents/` or `~/Library/Caches/` — your sandbox is writable, the bundle is not.

Edge cases I've hit on real engagements

  • An LLDB attach during launch invalidates the signature on devices with hardened runtime — disable LLDB auto-attach, or sign with the get-task-allow entitlement.
  • A Crashlytics post-build dSYM upload script accidentally `touch`ed a file inside the bundle when it should have only read symbols.
  • macOS Sequoia / iOS 18+ enforce `cs_blob` checks more strictly than older OS — code that 'worked' before now fails after an OS bump.
  • JIT-less Stikgame / certain hot-reload tools modify the bundle after install — see the JIT-less diagnose page mentioned in some of these errors.

Verify before pushing further

codesign --verify --deep --strict --verbose=2 "$BUILT_PRODUCTS_DIR/$WRAPPER_NAME"

Related fixes