Notarization Errors and How to Fix Them

Apple's notary service rejects a build with a status of Invalid and a short reason in its log. This page lists the errors developers hit most, what causes each one, and how to fix it. Each error text is quoted from Apple's documentation or from Apple's tools. Notarization is one step of distributing a macOS app outside the App Store.

Read the notarization log first

notarytool only tells you that a submission is Invalid. The reason is in the log:

xcrun notarytool submit MyApp.dmg --keychain-profile "notary" --wait
xcrun notarytool log <submission-id> --keychain-profile "notary" notary-log.json

The log is JSON. Each entry in issues has a message, the path of the file it is about, and a severity. Apple recommends that you always read the log, even when notarization succeeds, because it also lists warnings.

To see all your submissions and their status:

xcrun notarytool history --keychain-profile "notary"

The signature of the binary is invalid.

Something changed the bundle after you signed it. Apple also lists a missing signature as a cause, but for a Mach-O file with no signature, notary logs usually say The binary is not signed. instead. Common causes are a build script that copies a file into the app after signing, and a framework that you signed before you modified it.

Check the signature:

codesign -vvv --deep --strict MyApp.app

For an installer package, use pkgutil --check-signature MyApp.pkg. Sign again after the last change to the bundle.

The binary is not signed.

The file at path is a Mach-O binary that has no code signature. Usually this is code that you added to the bundle yourself: a command-line tool, a .dylib, a .so or .node module, or a bundled Python or Node runtime. The notary service also looks inside ZIP and JAR files in the bundle. The same path usually also gets the secure timestamp and hardened runtime errors.

Look at where the file is. codesign does not sign an app that has unsigned code in Contents/MacOS or Contents/Frameworks. But in Contents/Resources, codesign seals the file as data. The app signs without an error, and codesign --deep --strict passes. Put tools in Contents/MacOS or Contents/Helpers, and libraries in Contents/Frameworks. Keep only scripts and data in Contents/Resources. See Placing content in a bundle.

To list the unsigned Mach-O files:

find MyApp.app -type f -exec sh -c 'file -b "$1" | grep -q Mach-O && ! codesign -d "$1" 2>/dev/null && echo "$1"' _ {} \;

Sign each file with your Developer ID, -o runtime, and --timestamp. Start with the innermost files and sign the app last, as in Sparkle helpers. For code in a ZIP or JAR file, sign it before you pack the archive. The command above does not look inside archives.

The binary is not signed with a valid Developer ID certificate.

You signed with the wrong certificate type, for example Apple Development, Mac App Distribution, or a self-signed certificate. Sign apps and DMGs with Developer ID Application. Sign installer packages with Developer ID Installer.

codesign -dvv MyApp.app 2>&1 | grep Authority

The first Authority line must start with Developer ID Application:. If your certificate comes from the old Developer ID authority, also read Developer ID Certificates Expire February 1, 2027.

The signature does not include a secure timestamp.

A manual codesign step or a custom export left out the timestamp. Add --timestamp to every codesign command, or to OTHER_CODE_SIGN_FLAGS in Xcode. The Mac that signs needs internet access to timestamp.apple.com.

codesign -dvv MyApp.app 2>&1 | grep -E "Timestamp|Signed Time"

A Timestamp= line means the signature has a secure timestamp. A Signed Time= line means it does not.

The executable does not have the hardened runtime enabled.

Turn on the Hardened Runtime capability in Xcode, or add --options=runtime to your codesign command. Every executable in the bundle needs it, including helpers and XPC services inside frameworks. See Sparkle helpers below.

The executable requests the com.apple.security.get-task-allow entitlement.

This entitlement allows debuggers to attach, and the notary service rejects it. Xcode adds it to every build by default (CODE_SIGN_INJECT_BASE_ENTITLEMENTS=YES). Archive and export remove it. A custom workflow that ships the build product directly keeps it. Archive and export from Xcode, or set that build setting to NO for release builds.

The binary uses an SDK older than the 10.9 SDK.

Build against the macOS 10.9 SDK or later. This does not drop support for older systems: the deployment target, not the SDK, decides which macOS versions your app runs on.

Embedded entitlements are invalid

Apple describes this as an error "like" Embedded entitlements are invalid: syntax error near line 1. The entitlements in the signature are malformed. Usually they are a binary property list, or the file is not plain ASCII, for example because it starts with a byte order mark. Check for bplist00 in the output of:

codesign -d --entitlements :- MyApp.app

Current versions of codesign warn that the : form is deprecated, but it still works. The --xml replacement always prints XML, so it cannot show bplist00.

Convert the file to XML, check it, and sign again:

plutil -convert xml1 MyApp.entitlements
plutil -lint MyApp.entitlements

Notarization is stuck "In Progress"

Apple says notarization completes for most software within 5 minutes, and for 98 percent of software within 15 minutes. Some uploads are held for additional analysis. This happens most often to teams that notarize for the first time.

  • Wait. Apple's engineers say the delay usually clears itself in a day or two, and that delays become less frequent as the service learns your app.
  • There is no cancel. notarytool has no cancel command.
  • --timeout only stops waiting. The notary service continues to process the submission.
  • Escalate after a week. If all your requests stay In Progress for more than a week, post in the Apple Developer Forums under Code Signing > Notarization, with the submission UUID and the date of the first stuck request.

Apple's System Status page has a row for the Developer ID Notary Service. Apple also asks you to limit notarizations to 75 per day.

The staple and validate action failed! Error 65.

Error 65 is EX_DATAERR, "The ticket data is invalid." stapler could not get a ticket that matches the file, or it could not validate the ticket. In the first case, the log above the error usually says Record not found and Could not find base64 encoded ticket in response.

Usually no ticket exists: you did not notarize the file, or notarization failed. Check that the status is Accepted. If it is, you staple a different file than the one you submitted. If you sign a file again after notarization, its code directory hash changes and the ticket no longer matches. Staple exactly the file that the notary service accepted.

If the message says Could not validate ticket instead, stapler found the ticket, but trust evaluation failed. A common cause is changed trust settings on Apple's root certificates on this Mac. List them with security dump-trust-settings and security dump-trust-settings -d, and remove the custom trust settings in Keychain Access.

Other stapler exit codes. The man page names them from sysexits(3):

Error Meaning
66 The path cannot be found, is not code-signed, or is not a supported file format. With validate, the stapled ticket is missing or invalid.
68 The path was not notarized, or the ticket service returned an unexpected response.
73 The ticket could not be written to disk. The folder that contains the file must be writable.
77 The ticket service revoked the ticket.

You cannot staple a ZIP file. stapler needs network access to CloudKit over port 443. Signing a file again invalidates a ticket that is already stapled.

HTTP status code: 401. Invalid credentials.

The full message starts Error: HTTP status code: 401. Invalid credentials. Username or password is incorrect. Check these, in this order:

  1. You use an app-specific password from appleid.apple.com, not your Apple ID password.
  2. The team ID is correct, and you are a member of that team.
  3. With an App Store Connect API key, the key has the Developer, App Manager, or Admin role. Use a Team key: Apple's documents disagree on whether Individual keys work with notarytool. Do not pass --issuer with an Individual key, because that causes a 401 Unauthorized response.

If notarytool says Ensure your team has signed the necessary legal agreements and that they are not expired., the Account Holder must accept the current agreements in your developer account.

Test your credentials without a submission:

xcrun notarytool history --keychain-profile "notary"

To store credentials once, with an API key:

xcrun notarytool store-credentials "notary" \
  --key AuthKey_ABC123.p8 --key-id ABC123 --issuer <issuer-uuid>

For CI, see GitHub Actions, which uses an App Store Connect API key.

Sparkle helpers and XPC services

Sparkle ships its helpers (Autoupdate, Updater.app, Installer.xpc, Downloader.xpc) with an ad-hoc signature. If you sign the app yourself, sign each helper with your Developer ID, the hardened runtime, and a timestamp. Sign from the inside out, and sign the app last. These are Sparkle's commands for Sparkle 2.6 or later, plus the --timestamp that notarization needs:

ID="Developer ID Application: Your Name (TEAMID)"
FW=MyApp.app/Contents/Frameworks/Sparkle.framework
codesign -f -s "$ID" -o runtime --timestamp $FW/Versions/B/XPCServices/Installer.xpc
codesign -f -s "$ID" -o runtime --timestamp --preserve-metadata=entitlements $FW/Versions/B/XPCServices/Downloader.xpc
codesign -f -s "$ID" -o runtime --timestamp $FW/Versions/B/Autoupdate
codesign -f -s "$ID" -o runtime --timestamp $FW/Versions/B/Updater.app
codesign -f -s "$ID" -o runtime --timestamp $FW
codesign -f -s "$ID" -o runtime --timestamp --entitlements MyApp.entitlements MyApp.app

Apple says: do not pass --deep to codesign when you sign. It is fine for verification. Sparkle's docs say that Archive and Export in Xcode signs the helpers for you, but "Code Sign on Copy" does not.

“MyApp” is damaged and can’t be opened.

Users see this Gatekeeper alert, with the suggestion "You should move it to the Trash.", when the app's signature is broken. Usually a file was added or changed after signing, or a copy changed the Unicode normalization of a file name. Use ASCII file names in the bundle. Verify the app:

codesign -v -vvv --strict --deep MyApp.app

a sealed resource is missing or invalid in the output confirms the cause. Sign again after the last change, then notarize the new build. For the other causes of this alert, see “App Is Damaged and Can’t Be Opened”: The Fix for Mac Developers.

Apple could not verify “MyApp” is free of malware

Gatekeeper shows this when the app is not notarized, or when it cannot find the ticket. This happens when the ticket is not stapled and the Mac is offline, so Gatekeeper cannot get the ticket from Apple. Test the way your users get the app: download it with Safari so that it gets the quarantine flag, then run:

syspolicy_check distribution MyApp.app
spctl -a -t exec -vvv MyApp.app
spctl -a -t open -vvv --context context:primary-signature MyApp.dmg

syspolicy_check needs macOS 14 or later.

Skip the manual steps

Amore signs and notarizes every release as part of one command. Set it up in Code Signing and Notarization, then release with the CLI or GitHub Actions.

Sources