DEV Community

Jackson
Jackson

Posted on • Originally published at macless.dev

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

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
Enter fullscreen mode Exit fullscreen mode

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 fresh rather than debugging the existing value.

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:

  • The provisioning profile's name, as typed into your IOS_PROVISIONING_PROFILE_NAME variable/secret.
  • The bundle ID in IOS_BUNDLE_ID — it has to match the App ID the profile was actually generated for.

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.

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. 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.

I hit every one of these building the CI pipeline behind Citolex. Full writeup of the signing setup (and every other error this pipeline has produced) is at macless.dev.

Top comments (0)