ANTIGRAVITY LABJP
Articles/App Development
App Development/2026-06-27Advanced

When a Local iOS Build Passes but CI's TestFlight Upload Rejects the Signature — Field Notes on match Code-Signing Drift

Running fastlane match on CI can produce builds that succeed while only the TestFlight upload fails on signing. These field notes show how to diagnose the certificate/profile drift reproducibly, lock CI to readonly, and add a pre-upload gate that stops bad signatures before they reach Apple.

fastlane3matchiOS25code signingCI/CD15TestFlight2App Store Connect2

Premium Article

The first time I saw "build green, upload red"

What confused me most while staring at the CI log was this exact state: build_app ran to completion, the .ipa existed — and yet the very next step, upload_to_testflight, failed on a signing error. Building the same commit locally on my Mac sailed straight through to TestFlight.

Few bugs are more frustrating than the ones that won't reproduce on your own machine. I started by handing Antigravity the CI log, the Fastfile, and the Matchfile, asking it to "list the likely causes in order, separating what's verified at build-signing time from what's verified at distribution time, given that the build succeeds and the .ipa exists but only the upload fails on signing." Splitting the symptom into two stages — build signing vs. distribution-side validation — before touching anything saved me a lot of blind retries.

These notes are what survived that triage. They're for anyone using fastlane match whose signing behaves differently locally than it does on CI.


What's really happening: build and distribution inspect different certificates

The key thing to internalize is that producing an iOS .ipa and uploading it to App Store Connect validate different things at different times.

At build time, Xcode needs the specified provisioning profile to exist and the matching signing certificate (with its private key) to be present in the keychain. Satisfy that, and the .ipa gets built.

At upload time, App Store Connect re-validates that the profile and signature embedded in the .ipa don't conflict with the currently valid certificates, registered devices, and Bundle ID entitlements. A build that succeeds can absolutely be rejected at this second check.

Bring match into it and you add a third source of truth: the certificates stored in a Git repository. Your local keychain, the CI runner's temporary keychain, and the match Git repo — when all three point at the same certificate, you're fine. The moment any one of them drifts, you get the asymmetry where the build succeeds with an old certificate and the upload is rejected against newer entitlements. That asymmetry is the whole of "signing drift."

Here are the common ways it drifts:

Source of driftTypical triggerBuildUpload
match certificate regeneratedSomeone ran match nuke / match --force locallySucceeds on the old certRejected as revoked
Certificate expiredApple Distribution cert passed its one-year markCan succeed from cacheRejected
Profile/certificate mismatchAdded an Extension but didn't re-sync matchMain target succeedsRejected for missing Extension signature
CI keychain missing the certFetched with readonly: true but failed to import into the keychainFails earlierNever reached

The first two rows are the interesting ones. The build succeeds but the upload fails precisely because an old or expired certificate lingering in the local or CI keychain is enough to satisfy the build. It isn't that the failure won't reproduce — it's that only the reproducing environment is carrying the stale certificate.


Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
Why a build can succeed while the upload fails, and how to identify exactly which certificate and profile were embedded in the .ipa
Concrete Fastfile / GitHub Actions settings to run match readonly on CI so certificate regeneration can't invalidate existing builds
A pre-upload action that inspects the embedded provisioning profile and certificate expiry, failing fast on any mismatch
Secure payment via Stripe · Cancel anytime

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Antigravity Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

Related Articles

App Dev2026-05-06
Automate Unity CI/CD with Antigravity and GitHub Actions: A Practical Guide
Set up a complete Unity CI/CD pipeline using GameCI, GitHub Actions, and Antigravity — from automated testing to TestFlight uploads. A practical guide for indie developers who want to stop building manually.
App Dev2026-04-01
App Store Connect 2026 Update: 100+ New Metrics and How to Use Them with Antigravity
Apple overhauled App Store Connect in March 2026 with 100+ new metrics. Learn how to leverage these insights with Antigravity to automate app analytics and build a data-driven improvement cycle.
App Dev2026-06-23
My Daily Wallpaper Widget Stopped Updating — Measuring WidgetKit's Reload Budget and Rebuilding the Design
A widget that was supposed to rotate the wallpaper every day froze after a few days. Here is how I measured WidgetKit's timeline reload budget and extension memory limit, then rebuilt the design around a single daily timeline.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →