From time to time I see folks run into error 65 when stapling a ticket to their notarised Mac software. This post explains the two common causes of that error.
If you have questions or comments, start a new thread here on the forums. Put it in the Code Signing > Notarization topic area so that I see it.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
Resolving Error 65 When Stapling
If you directly distribute Mac software, you must sign and notarise your product so that it passes Gatekeeper. For information on how to do this, see:
-
Notarizing macOS software before distribution, if you use Xcode
-
Creating distribution-signed code for macOS, Packaging Mac software for distribution, and Customizing the notarization workflow otherwise
The last step of that process is to staple a ticket to your notarised product. This can fail with error 65. There are two common causes of that failure:
-
No appropriate ticket
-
Trust issues
The following sections explain how to recognise and resolve these issues.
Note You are not absolutely required to staple your product. See The Pros and Cons of Stapling for more on that topic.
No Appropriate Ticket
Consider the following stapling error:
% stapler staple "TestError65.dmg"
Processing: /Users/quinn/Desktop/TestError65 2025-03-03 22-12-47/TestError65.dmg
CloudKit query for TestError65.dmg (2/d812985247c75e94fd603f026991f96144a031af) failed due to "Record not found".
Could not find base64 encoded ticket in response for 2/d812985247c75e94fd603f026991f96144a031af
The staple and validate action failed! Error 65.
Note the Record not found
message. This indicates that the stapling operation failed because there’s no appropriate ticket.
To investigate this, look at the notary log:
% notarytool-log b53042b6-4cbb-4cef-ade4-dae034a69947
{
…
"status": "Accepted",
…
"sha256": "f012735a6d53b17082c088627da4249c9988111d17e7a90c49aa64ebc6bae22e",
"ticketContents": [
{
"path": "TestError65.dmg/TestError65.app",
"digestAlgorithm": "SHA-256",
"cdhash": "abc27b0f2daee77b9316de3c6844fbd9e234621c",
"arch": "x86_64"
},
{
"path": "TestError65.dmg/TestError65.app",
"digestAlgorithm": "SHA-256",
"cdhash": "9627c72e53d44ae77513613e2ce33314bd5ef41e",
"arch": "arm64"
},
{
"path": "TestError65.dmg/TestError65.app/Contents/MacOS/TestError65",
"digestAlgorithm": "SHA-256",
"cdhash": "abc27b0f2daee77b9316de3c6844fbd9e234621c",
"arch": "x86_64"
},
{
"path": "TestError65.dmg/TestError65.app/Contents/MacOS/TestError65",
"digestAlgorithm": "SHA-256",
"cdhash": "9627c72e53d44ae77513613e2ce33314bd5ef41e",
"arch": "arm64"
},
{
"path": "TestError65.dmg",
"digestAlgorithm": "SHA-256",
"cdhash": "01a553c91ee389764971767f5082ab8c7dcece02"
}
],
"issues": null
}
First, make sure that the status
field is Accepted
. If there’s some other value, the notary service didn’t generate a ticket at all! To understand why, look at the rest of the notary log for errors and warnings.
Assuming that your notarisation request was successful, look through the log for cdhash values. These represent the contents of the ticket generated by the notary service. Compare that list to the cdhash values of the code being signed:
% hdiutil attach "TestError65.dmg"
…
… /Volumes/Install TestError65
% codesign -d -vvv --arch arm64 "/Volumes/Install TestError65/TestError65.app"
…
CDHash=9627c72e53d44ae77513613e2ce33314bd5ef41e
…
% codesign -d -vvv --arch x86_64 "/Volumes/Install TestError65/TestError65.app"
…
CDHash=abc27b0f2daee77b9316de3c6844fbd9e234621c
…
Those are all present in the ticket. However, consider the cdhash of the disk image itself:
% codesign -d -vvv "TestError65.dmg"
…
CDHash=d812985247c75e94fd603f026991f96144a031af
…
That’s the cdhash that stapler
is looking for:
CloudKit query for TestError65.dmg (2/d812985247c75e94fd603f026991f96144a031af) failed due to "Record not found".
But it’s not present in the notarised ticket.
Note The term cdhash stands for code directory hash. If you’re curious what that’s about, see TN3126 Inside Code Signing: Hashes and the Notarisation Fundamentals DevForums post.
What happened here is:
-
I built the app.
-
I signed it with my Developer ID code-signing identity.
-
I created a disk image from that app.
-
I signed that with my Developer ID code-signing identity.
-
I notarised that.
-
I then re-signed the disk image. This changes the cdhash in the code signature.
-
Now the disk image’s cdhash doesn’t match the cdhash in the ticket, so stapling fails.
To resolve this problem, make sure you’re stapling exactly the file that you submitted to the notary service. One good option is to compare the SHA-256 hash of the file you’re working on with the sha256
field in the notary log.
Trust Issues
Now consider this stapling error:
% stapler staple "TestError65.dmg"
Processing: /Users/quinn/TestError65.dmg
Could not validate ticket for /Users/quinn/TestError65.dmg
The staple and validate action failed! Error 65.
Note how it’s different from the previous one. Rather than saying that the ticket was not found, it says Could not validate ticket
. So, stapler
found the ticket for the file and then tried to validate it before doing the staple operation. That validation failed, and thus this error.
The most common cause of this problem is folks messing around with trust settings. Consider this:
% security dump-trust-settings
SecTrustSettingsCopyCertificates: No Trust Settings were found.
% security dump-trust-settings -d
SecTrustSettingsCopyCertificates: No Trust Settings were found.
Contrast it with this:
% security dump-trust-settings
SecTrustSettingsCopyCertificates: No Trust Settings were found.
% security dump-trust-settings -d
Number of trusted certs = 1
Cert 0: Apple Root CA - G3
Number of trust settings : 10
…
Someone has tweaked the trust settings for the Apple Root CA - G3 anchor. In fact, I used Keychain Access to mark the certificate as Always Trust. You’d think that’d avoid problems, but you’d be wrong. Our code signing machinery expects Apple’s anchor and intermediate certificates to have the default trust settings.
IMPORTANT Some trust settings overrides are fine. For example, on my main work Mac there are trust settings overrides for Apple internal anchors. This problem occurs when there are trust settings overrides for Apple’s standard anchor and intermediate certificates.
To fix this:
-
In Terminal, run the
dump-trust-settings
commands shown above and build a list of Apple certificates with trust settings overrides. -
In Keychain Access, find the first problematic certificate in your list.
Note that there may be multiple instances of the certificate in different keychains. If that’s the case, follow these steps for each copy of the certificate.
-
Double click the certificate to open it in a window.
-
If the Trust section is collapsed, expand it.
-
Ensure that all the popups are set to their default values (Use System Defaults for the first, “no value specified” for the rest).
-
If they are, close the window and move on to step 8.
-
If not, set the popups to the default values and close the window. Closing the window may require authentication to save the trust settings.
-
Repeat steps until 2 through 7 for each of the problematic certificates you found in step 1.
-
When you’re done, run the
dump-trust-settings
commands again to confirm that your changes took effect.