LEARN · DEBUGGING GUIDE

iOS Code Signing Error in Xcode: A Debugging Guide

Code signing errors in Xcode are almost always mismatched certificates, expired profiles, or incorrect bundle IDs. This guide walks through diagnosis and fixes with real commands and a war story from production.

IntermediateMobile8 min read

What this usually means

Code signing errors indicate a mismatch between the signing assets Xcode expects and what is available in your Apple Developer account or local keychain. Common reasons: expired certificates, revoked profiles, mismatched bundle identifiers, or incorrect team selected in project settings. The signing system has five moving parts—developer certificate, private key, provisioning profile, app ID, and device list—and if any one is out of sync, the build fails. Xcode's automatic signing often masks these issues until a manual archive or CI run exposes them. The root is always a gap between what Apple's portal says you have and what your Mac's keychain and Xcode project settings reference.

( 01 )Fast diagnosis

The first ten minutes — establish facts before touching code.

  • 1Run `security find-identity -v -p codesigning` to list valid signing certificates and their SHA-1 hashes.
  • 2Check the provisioning profile's expiration: `security cms -D -i ~/Library/MobileDevice/Provisioning\ Profiles/<profile>.mobileprovision | grep -A1 ExpirationDate`.
  • 3Open Xcode -> Preferences -> Accounts -> Select Apple ID -> View Details, then verify certificates and profiles listed match your Developer Portal.
  • 4Clean build folder (`Cmd+Shift+K` + `Cmd+Option+Shift+K`), then rebuild with build logging: `xcodebuild -workspace App.xcworkspace -scheme App -sdk iphoneos -allowProvisioningUpdates build 2>&1 | grep -i error`.
  • 5Compare the bundle identifier in your target's General tab with the App ID in the provisioning profile: `grep -A1 application-identifier ~/Library/MobileDevice/Provisioning\ Profiles/*.mobileprovision`.
( 02 )Where to look

The specific files, logs, configs, and dashboards that usually own this bug.

  • searchKeychain Access: ~/Library/Keychains/login.keychain-db — look for expired or missing private keys.
  • searchProvisioning profiles directory: ~/Library/MobileDevice/Provisioning\ Profiles/ — check for .mobileprovision files with correct App ID.
  • searchApple Developer Portal -> Certificates, Identifiers & Profiles -> Profiles — verify profile status (Active/Expired).
  • searchXcode project file (project.pbxproj) — search for CODE_SIGN_IDENTITY, PROVISIONING_PROFILE_SPECIFIER, and DEVELOPMENT_TEAM.
  • searchBuild log: DerivedData/Logs/Build/*.xcactivitylog — extract raw error messages with `grep -a 'signing'`.
  • searchCI environment: env vars like `CODE_SIGN_IDENTITY`, `PROVISIONING_PROFILE_SPECIFIER` — override project settings.
( 03 )Common root causes

Practical causes, not theory. These are the things you will actually find.

  • warningExpired Apple Developer Enterprise or Distribution certificate (valid for 1–3 years).
  • warningProvisioning profile expired or revoked after device changes or new certificate generation.
  • warningPrivate key missing from keychain after Mac migration or keychain cleanup.
  • warningBundle identifier mismatch between Xcode target and App ID in provisioning profile.
  • warningTeam ID in Xcode project points to a different Apple Developer account than the profile belongs to.
  • warningMultiple distribution certificates in keychain cause Xcode to pick the wrong one.
( 04 )Fix patterns

Concrete fix directions. Pick the one that matches your root cause.

  • buildRevoke all old certificates in Developer Portal, generate new ones, download and double-click to install into keychain. Then regenerate provisioning profiles using the new certificate.
  • buildDelete all expired provisioning profiles from ~/Library/MobileDevice/Provisioning\ Profiles/ and let Xcode download fresh ones via Preferences -> Accounts -> View Details -> Download Manual Profiles.
  • buildSwitch to manual signing: set 'Signing Certificate' to 'iOS Distribution' and 'Provisioning Profile' to the correct UUID. This bypasses Xcode's automatic matching logic.
  • buildExport the developer certificate and private key from a working Mac via Keychain Access -> Right-click -> Export, then import on the broken Mac.
  • buildIn CI, set `xcodebuild` with `CODE_SIGN_STYLE=Manual`, `PROVISIONING_PROFILE_SPECIFIER=`, and `DEVELOPMENT_TEAM=` explicitly to avoid environment mismatch.
  • buildUse `fastlane match` or `fastlane sigh` to centralize certificate and profile management, ensuring all machines use the same assets.
( 05 )How to verify

A fix you cannot prove is a guess. Close the loop.

  • verifiedBuild and archive successfully from Xcode with 'Generic iOS Device' selected and no signing errors.
  • verifiedRun `xcodebuild -workspace App.xcworkspace -scheme App -sdk iphoneos -allowProvisioningUpdates archive` and confirm it exits 0.
  • verifiedInstall the IPA on a device via Xcode's Devices window or `ios-deploy`; check that the app launches without 'unable to verify code signature'.
  • verifiedVerify the signing certificate in the IPA: `codesign -d -vvvv /path/to/App.app` shows valid TeamIdentifier and authority chain.
  • verifiedCheck CI logs for 'Code Signing' step passing with the correct certificate and profile UUID.
( 06 )Mistakes to avoid

Things that make this bug worse or harder to find.

  • warningDon't delete provisioning profiles from the Developer Portal while old profiles are still on your Mac—Xcode might have cached the old UUID. Instead, download fresh profiles first.
  • warningDon't use 'Automatically manage signing' for production archives if you have multiple teams or certificates—it often picks wrong.
  • warningDon't ignore the 'PEM' or 'private key not found' warnings in Keychain Access; a missing private key renders the certificate useless.
  • warningDon't copy .mobileprovision files from another Mac without checking the embedded certificate—it's tied to the original developer's private key.
  • warningDon't set PROVISIONING_PROFILE_SPECIFIER to 'Automatic' in CI—specify the exact profile name or UUID.
  • warningDon't revoke a certificate without first ensuring all provisioning profiles using it are regenerated, or builds will break immediately.
( 07 )War story

The CI Build That Suddenly Failed for No Reason

Mobile DevOps EngineeriOS 14, Xcode 12.4, Jenkins, Fastlane, GitHub Enterprise

Timeline

  1. 09:15CI build fails on main branch with 'No matching provisioning profiles found for App-Store'.
  2. 09:20Developer checks Xcode on his Mac — builds fine. Points at CI environment.
  3. 09:35I SSH into CI node, run `security find-identity -v -p codesigning` — shows one valid distribution cert.
  4. 09:50Check provisioning profiles directory — only 3 profiles, all for development, none for distribution.
  5. 10:00Open Developer Portal — Distribution profile is marked 'Expired' (expired 2 days ago).
  6. 10:10Generate new distribution profile, download, place into CI's provisioning profiles folder.
  7. 10:15Retry build — fails with 'Valid signing identity not found'.
  8. 10:25Check keychain: distribution cert is there, but private key is missing (exported from old Mac, never imported to CI).
  9. 10:40Export private key from working Mac, import via `security import` on CI.
  10. 10:45Retry build — succeeds.

I was the mobile DevOps engineer on a team of ten iOS developers. Our CI ran on a shared Jenkins node, and we used Fastlane for builds. One morning, the main branch build started failing with a classic code signing error: 'No matching provisioning profiles found for App-Store'. The developer who pushed the last commit claimed it built fine on his machine, which is always the first red flag. I SSH'd into the CI node to investigate.

First, I checked the signing identities with `security find-identity -v -p codesigning`. It showed one distribution certificate, which looked okay. Then I looked at provisioning profiles in `~/Library/MobileDevice/Provisioning Profiles/`. There were only three files, all development profiles. That's when I realized the distribution profile must have expired. Logged into the Apple Developer Portal and confirmed: the App Store distribution profile expired two days ago. I generated a new one and placed it on the CI node.

But the next build failed with 'Valid signing identity not found'. That was weird because the certificate was there. I double-checked the keychain: the certificate was present, but when I expanded it, there was no private key underneath. The private key had been exported from the original developer's Mac but never imported to the CI node after a keychain cleanup. I exported the private key from my own Mac (which had it), imported it on the CI via `security import mykey.p12 -k ~/Library/Keychains/login.keychain`, and the next build passed. The root cause was expired profile plus missing private key — two separate issues that compounded.

Root cause

Provisioning profile had expired, and the distribution certificate's private key was missing from the CI node's keychain.

The fix

Generated a new distribution profile from Apple Developer Portal, imported the missing private key (.p12) into the CI keychain.

The lesson

Always check both certificate and private key separately. Use a centralized signing management tool like Fastlane Match to avoid manual keychain management on CI nodes.

( 08 )Understanding the Code Signing Chain

iOS code signing involves a chain of trust: Apple issues a certificate to a developer, the developer signs the app binary, and a provisioning profile ties together the certificate, app ID, and devices. The private key must be present in the keychain for the certificate to be usable. Xcode matches provisioning profiles based on bundle ID, team, and certificate type. When any link breaks — expired cert, missing key, mismatched profile — you get a signing error.

The most non-obvious failure is when Xcode's automatic signing picks a different certificate than expected. For example, if you have both a development and distribution certificate for the same team, Xcode might choose the wrong one for archiving. Always use manual signing for production builds to avoid ambiguity.

( 09 )Diagnosing Private Key Issues

A missing private key is the silent killer. The certificate appears valid in Keychain Access, but any signing operation fails. To verify, open Keychain Access, find the certificate under 'My Certificates', expand it. If there's no disclosure triangle with a private key, it's missing. Alternatively, run `security find-identity -v -p codesigning` — identities that can sign are listed with a SHA-1 hash; if the certificate appears but without a hash, the private key is absent.

To recover, locate the original .p12 file from the machine that generated the CSR (Certificate Signing Request). If that machine is gone, you must revoke the certificate in Developer Portal, create a new one, and regenerate all provisioning profiles. There is no way to recover a lost private key.

( 10 )Provisioning Profile Expiration vs. Certificate Expiration

Profiles and certificates have independent expiration dates. A profile can expire while the certificate is still valid, and vice versa. When a profile expires, builds fail with 'No matching provisioning profiles found'. When a certificate expires, you get 'No signing certificate found'. Always check both in Developer Portal. The profile expiration is visible in its details page; certificate expiration is under 'Certificates'.

A common pitfall: regenerating a profile without updating the certificate first. If the certificate expires soon, the new profile will also stop working when the cert expires. Best practice is to set calendar reminders for renewal dates and use Fastlane Match to automate renewal.

( 11 )CI/CD Specific Signing Gotchas

CI nodes often have bare keychains with no user interaction. Common issues: missing developer certificate, wrong keychain unlocked, or environment variables overriding project settings. Use `security unlock-keychain -p <password> ~/Library/Keychains/login.keychain` before builds. For Jenkins, install the certificate and private key via a credential plugin or a pre-build script.

Another gotcha: Xcode's `-allowProvisioningUpdates` flag can download profiles automatically, but only if the machine has the correct team and the Apple ID is logged in. For headless CI, use `xcodebuild` with explicit `PROVISIONING_PROFILE_SPECIFIER` and `CODE_SIGN_IDENTITY` to avoid relying on automatic matching. Fastlane's `match` or `sigh` can import profiles securely.

( 12 )Entitlements Mismatch

Sometimes the signing error mentions entitlements like 'aps-environment' or 'com.apple.developer.associated-domains'. This happens when the provisioning profile doesn't include capabilities that the app's entitlements file requests. The fix: enable the capability in Xcode's Signing & Capabilities tab, which regenerates the profile with the correct entitlements. For manual profiles, ensure the App ID in Developer Portal includes the needed capabilities.

Check the entitlements file in your project (usually in the project root or target directory). Compare with the profile's embedded entitlements: run `security cms -D -i profile.mobileprovision | plutil -p - | grep -A100 Entitlements`.

Frequently asked questions

How do I find the exact provisioning profile UUID that Xcode is using?

Build your project and look in the build log for 'Provisioning profile UUID' or run `xcodebuild -showBuildSettings | grep PROVISIONING_PROFILE`. You can also inspect the .app bundle: `codesign -d --entitlements - /path/to/App.app | grep application-identifier`.

What if I have multiple distribution certificates for the same team?

Xcode may pick the wrong one. Use manual signing and set CODE_SIGN_IDENTITY to the certificate's common name (e.g., 'iPhone Distribution: Company Name (TEAMID)'). To list exact names: `security find-identity -v -p codesigning | grep "iPhone Distribution"`.

Why does my app build on one Mac but not another?

The working Mac has the correct private key and profile; the failing one does not. Export the certificate and private key from the working Mac (Keychain Access -> My Certificates -> Export), transfer the .p12, and import on the failing Mac. Also copy the provisioning profile from `~/Library/MobileDevice/Provisioning Profiles/` or download fresh from Apple Developer.

Can I use a free Apple ID for code signing?

Yes, but free accounts have restrictions: profiles expire every 7 days, and you can only deploy to your own devices. For production or CI, you need a paid Apple Developer account ($99/year). Free accounts also cannot use certain capabilities like Push Notifications or iCloud.

What does 'An error occurred during code signing' mean in Xcode 13+?

This generic error often hides a more specific reason. Look in the Report navigator (Cmd+9) or run the build from terminal with `xcodebuild` to see the full error. Common hidden causes: expired certificate, private key not found, or profile not installed.