Code signatures carry a format version, and Apple retires old versions. This message is the operating system saying it read the signature, understood enough of it to identify the format, and declined to accept it. Your certificate is almost certainly fine. Issuing a new one changes nothing, which is the first thing most people try.
Two tightenings account for nearly every occurrence in the wild. On macOS, version 1 signatures, the kind produced before OS X Mavericks, stopped being recognised years ago, and signatures whose code directory only carries a SHA-1 hash have been refused since the SHA-256 transition. On iOS 15, watchOS 8, and tvOS 15, Apple began requiring entitlements to be embedded in DER form as well as the old plist form, and an app signed by a toolchain that never emitted DER entitlements will not install.
That second one is why a wave of these appeared around Xcode 12.5. The relevant codesign flag is --generate-entitlement-der, which Xcode 13 and later pass by default. If you are still driving codesign by hand from a script written before then, your script is probably not passing it.
Find which part of the bundle is at fault
The error names the app, but the offending signature is often on something nested inside it. Check the app, then every framework and dylib it embeds.
APP=build/MyApp.app # The app's own signature codesign -d -vvv "$APP" 2>&1 | grep -E "CodeDirectory|Signature|Hash" # Everything embedded for f in "$APP"/Frameworks/*; do echo "== $f" codesign -d -vvv "$f" 2>&1 | grep -E "CodeDirectory|Hash type" done
The CodeDirectory line prints a version number and a hash type. Rather than memorising which numbers are acceptable this year, sign a scratch binary on the same machine and compare: anything in your bundle reporting a lower version or a sha1-only hash type is the thing to re-sign. A vendored framework that reports a much older version than everything around it is your answer.
Re-sign it properly
The reliable fix is to let the current Xcode sign everything as part of a normal build. In the target's General tab, any embedded framework set to Embed Without Signing keeps whatever signature the vendor shipped, and that is exactly the state that produces this error. Switch it to Embed and Sign.
- 1
Update the machine doing the signing
Both macOS and Xcode. A signature is only as current as the codesign that produced it, and an old build agent quietly signing with an old toolchain is the most common cause on CI.
- 2
Set vendored frameworks to Embed and Sign
General tab, Frameworks, Libraries, and Embedded Content. This makes Xcode re-sign the framework with your identity during the build, replacing the vendor's stale signature.
- 3
Ask the vendor for an xcframework
A modern xcframework built on a current toolchain avoids the problem at source. Prebuilt .framework binaries handed over as zip files are where old signatures live longest.
- 4
Clean and rebuild before testing
Derived data holds the previously signed copies. A clean build folder is the difference between testing your fix and testing the old artifact.
If you must re-sign an existing artifact rather than rebuild it, sign from the inside out: every nested framework first, then the app last. Signing the app first invalidates the moment you touch something inside it. Use codesign directly rather than --deep, which applies one identity and one entitlement set to everything it walks and is not recommended by Apple for distribution.
IDENTITY="Apple Distribution: Acme Corp (ABCDE12345)" # Nested code first find build/MyApp.app/Frameworks -name "*.framework" -o -name "*.dylib" | while read -r f; do codesign --force --timestamp --sign "$IDENTITY" "$f" done # Then the app itself, with its own entitlements codesign --force --timestamp \ --entitlements build/MyApp.app.xcent \ --sign "$IDENTITY" \ build/MyApp.app
Checking your work
# Strict validation, the way the OS will do it codesign --verify --deep --strict --verbose=2 build/MyApp.app # Are DER entitlements present? codesign -d --entitlements - build/MyApp.app
A clean --verify --strict run on a current macOS is a good proxy for whether the device will accept it. It is not a guarantee, because the device also checks the profile and the device list, but a bundle that fails here will certainly fail there.
Related messages
- "This app cannot be installed because its integrity could not be verified." The device-side wording for a broader family of signature problems, of which this is one.
- If the install fails on profile grounds rather than signature format, you want A valid provisioning profile for this executable was not found.
- If codesign refuses to sign at all rather than the device refusing to install, check resource fork, Finder information, or similar detritus not allowed.
- On macOS the equivalent user-facing rejection comes from Gatekeeper rather than from the install daemon, and is usually a notarization problem instead.