Macless
Blog $99, one-time →
← All posts
Troubleshooting

Fix "No signing certificate matching team ID" in GitHub Actions

Three things actually cause this, and one log line tells you which one before you start regenerating things at random.

If you're building an iOS app in GitHub Actions (or any headless CI, really) and your archive/export step fails with something like No signing certificate "iOS Distribution" matching team ID "XXXXXXXXXX" with a private key was found, the good news is this is almost never a code problem. It's a mismatch somewhere between what Apple's portal has on file and what your CI job is trying to use.

In practice it's one of three things. Check them in this order — it's the order they're easiest to rule out in.

1. Check whether the certificate actually imported

Before anything else, open the "Import signing certificate" (or equivalent keychain-setup) step in your Actions log. It prints the identities it actually found after importing your .p12 file — something like:

1) AB12CD34EF... "Apple Distribution: Your Name (XXXXXXXXXX)"
     1 valid identities found

If that list is empty, or the identity isn't there at all, stop looking at provisioning profiles — the certificate itself didn't import. Usual causes: the base64-encoded .p12 secret got truncated or corrupted when it was pasted into GitHub Secrets, or the .p12 password secret is wrong. Re-export the certificate from Keychain Access (or wherever you generated it) and re-encode it fresh rather than debugging the existing value — it's faster than trying to figure out where a few bytes went missing.

2. Confirm the certificate and profile actually match

A provisioning profile isn't generic — it's generated against one specific signing certificate. If the identity from step 1 did import successfully, the next most common cause is that the certificate on Apple's portal was regenerated (often because the old one expired) without regenerating the profile that references it. Profiles pin to a certificate's public key; once that certificate is gone, every profile built against it silently stops working, even though the profile itself hasn't "expired" and still shows as valid in the portal.

The fix: in Apple's developer portal, open the provisioning profile, and regenerate it (this re-links it to your current active certificate), then re-download it and update the base64 secret your workflow uses.

3. Check the profile name and bundle ID match exactly

The third cause is the most tedious to catch because it fails silently on typos. Two things have to match character-for-character, including case and whitespace, between Apple's portal and your CI configuration:

Copy both values directly out of the Apple Developer portal rather than retyping them from memory — that's the single easiest place a mismatch sneaks in.

If you've checked all three and it's still failing: double-check you're not mixing up an "Apple Development" certificate with an "Apple Distribution" one — TestFlight and App Store builds need Distribution, not Development, and the error message doesn't always make that obvious. It's worth re-reading the exact certificate type in your import log against what your provisioning profile expects.

Why this happens more in CI than in Xcode

Xcode's GUI does a lot of this matching for you automatically when "Automatically manage signing" is on — it'll silently regenerate or fix up mismatched profiles in the background. CI has none of that; it uses exactly the certificate and profile you hand it, which is more predictable once it's working but means every mismatch surfaces as a hard failure instead of getting quietly patched over.

This is covered end-to-end in the template

I hit every one of these while building the CI pipeline behind Citolex. The signing script and troubleshooting doc in Macless walk through generating certificates and profiles correctly the first time, plus every error message this pipeline has actually produced.

See what's included — $99