Notarization rejected? How to read the notarytool log

Updated · Dmytro Virych

Guide · 3 min read

When notarization comes back Invalid, run xcrun notarytool log with the submission id to download a JSON file, then read its issues array, where each entry gives a message, the path of the file at fault and a severity.

You uploaded a build, waited, and notarytool reported a status other than "Accepted". The status line does not say what is wrong. The log does.

How do you get the log?

Every submission has an id. notarytool submit prints it, and Apple's documentation says to save it for later. With that id, ask for the log:

xcrun notarytool log 2efe2717-52ef-43a5-96dc-0797e4ca1041 \
  --keychain-profile "notarytool-password" developer_log.json

Apple describes the result as "JSON-formatted data" saved to the file you name, listing "any errors or warnings that occurred during notarization". The --keychain-profile name is whatever you gave notarytool store-credentials. Apple's own example log for a failed submission looks like this, trimmed:

{
  "issues": [
    {
      "message": "The signature of the binary is invalid.",
      "path": "Overnight TextEditor.app/Contents/MacOS/Overnight TextEditor",
      "severity": "error"
    }
  ],
  "status": "Invalid",
  "statusSummary": "Archive contains critical validation errors"
}

Read issues from the top. Each entry names the message, the path of the file inside your archive that caused it, and a severity. Fix what the log reports, then submit again: Apple's instruction is to "fix any problems reported by the service and notarize your app again".

The log is also worth reading on a submission that was accepted. Apple's advice for software that was already shipping is to "always review the notary log for any warnings".

What do the common errors mean, and how do you fix each?

These are the messages Apple's "Resolving common notarization issues" page lists, with the fix it gives for each.

Message in the logCauseFix
The signature of the binary is invalid.The code was never signed, or the bundle was modified after signing.Sign again as the last step, then test with codesign -vvv --deep --strict.
The binary is not signed with a valid Developer ID certificate.Signed with another kind of certificate, such as a Mac App Distribution or self-signed one.Sign with a Developer ID Application certificate (a Developer ID Installer certificate for installer packages).
The signature does not include a secure timestamp.A custom export process left out the timestamp.Pass the timestamp option to codesign, or add it to OTHER_CODE_SIGN_FLAGS.
The executable requests the com.apple.security.get-task-allow entitlement.The debugging entitlement Xcode injects into new projects reached the shipping build.Archive or export from Xcode, or set CODE_SIGN_INJECT_BASE_ENTITLEMENTS to NO for the distribution build.
The binary uses an SDK older than the 10.9 SDK.The binary was linked against a very old SDK.Rebuild with the macOS 10.9 SDK or later. Apple notes a newer SDK does not change which macOS versions run the app; the deployment target does.
The executable does not have the hardened runtime enabled.The hardened runtime capability is off.Turn it on in Xcode's capabilities, or add --options=runtime to OTHER_CODE_SIGN_FLAGS.
Embedded entitlements are invalid: syntax error near line 1The entitlements were embedded as a binary property list.Convert with plutil -convert xml1 and check with plutil -lint.

How do you check for each one yourself, before uploading?

Apple documents a command for most of these. Run them on the app you are about to submit.

# Signature valid, including nested code, with notarization's strictness
codesign -vvv --deep --strict /path/to/MyApp.app

# Secure timestamp: look for a Timestamp line, not "Signed Time"
codesign -dvv /path/to/MyApp.app

# Entitlements as embedded: output containing bplist00 will be rejected
codesign -d --entitlements :- /path/to/MyApp.app

# Would the system's policy let this run?
spctl -vvv --assess --type exec /path/to/MyApp.app

Two details from Apple's page are easy to miss. For the timestamp check, "the presence of Signed Time in the output indicates the binary doesn't have a secure timestamp", while a good signature shows a Timestamp value. And a secure timestamp needs internet access when you sign, because macOS accepts only one timestamp server, timestamp.apple.com. A signing step on a locked-down build machine can fail for that reason alone.

For an installer package, use pkgutil --check-signature instead. Apple says a properly signed package shows "Signed with a trusted timestamp" and "Developer ID Installer".

Why does it fail only in my scripted build?

Apple's page says Xcode "automatically resolves many issues" when you use its standard distribution workflow. Several rows in the table above, the timestamp and get-task-allow in particular, are problems that appear when a custom export process skips something Xcode would have done. If the Organizer route notarizes cleanly and your script does not, compare what your script leaves out.

What if the log shows an error not listed here?

Apple's page covers the common cases only. Read the message and path in your own log first: the path tells you which nested file to inspect with the commands above. Then look for the exact message in Apple's documentation before changing anything else.

#notarization#codesign#notarytool

Sources