TestFlight Build Expired — What to Do Next

Testers see "This beta has expired" or the build shows Expired in App Store Connect. Why it happens and how to push a replacement fast.

A tester messages you: “Your beta won’t open anymore — it says ‘This beta has expired.’” You open App Store Connect → TestFlight → Builds, and the build that’s been running smoothly for two months now shows status Expired. A few testers can still launch it for a short window (the binary stays cached on-device until the next TestFlight refresh), but new installs and most existing ones are blocked. Your external test cycle just paused, and there is no button to “extend” the dead build.

Fastest fix: you can’t revive an expired build — upload a new build with a higher build number, then attach it to the same tester group. If it’s the same version (e.g. still 2.7), a higher build number usually goes live in minutes without re-review. If it’s a new version (2.72.8), the first build of that version needs Beta App Review first — typically cleared within 24 hours as of June 2026.

Why TestFlight builds expire

TestFlight builds have a fixed 90-day lifetime measured from the upload date, not from first install. Apple documents this explicitly and enforces it strictly: there are no per-account exceptions and no way to extend a build past day 90. The clock is purely about the binary’s age — once it hits 90 days, App Store Connect flips its status to Expired and the TestFlight app refuses to launch it with “This beta has expired.”

This is not a bug or a sign anything is wrong with your app. It’s the intended behavior, and the only fix is to replace the expired binary with a fresh one.

Which bucket are you in?

Match your situation to the right next move before you start.

Symptom in App Store ConnectRoot causeFastest fix
Build is 90+ days old, status Expired, no newer build existsNever rotated to a new buildUpload a new build (Step 2 below)
A newer build exists, status Ready to Submit, but testers can’t see itNew build never attached to the groupAttach it to the group (Step 5)
Newer build status Waiting for Beta App ReviewNew version queued for reviewUse Internal Testing as a stopgap; wait out review
Newer build was added then withdrawn; testers fell back to old oneRotation gap during a regression fixRe-attach a non-expired build, or upload a new one
Testers in one group see it, another group doesn’tNew build attached to only some groupsAdd the build to every active group

1. Build hit the 90-day TestFlight lifetime cap

The 90-day clock starts at upload. After 90 days, Apple marks the build Expired and the TestFlight app rejects launches.

How to spot it: App Store Connect → TestFlight → Builds. Open the build and read its upload date. If it’s 85+ days ago, expiration is imminent or already happened. The same screen shows an explicit expiration date for each build.

2. No newer build was uploaded before expiration

You shipped one build for a long beta cycle and never rotated. Day 91 hits, the build expires, testers are locked out, and you have no fallback build ready.

How to spot it: In the TestFlight → Builds list, count how many builds are still inside their 90-day window. If you have only one and it’s old, you’re at risk.

3. Old build kept active while the newer one was withdrawn

You uploaded a newer build, made it available, then discovered a regression and removed it from the group. Testers fall back to the older build, which then expires while you’re still iterating on the fix.

How to spot it: The build’s Activity / version history shows a recent “withdrawn” action. If the only currently available build is older than 60 days, you have a rotation gap.

4. New build uploaded but never attached to the tester group

You uploaded a fresh build, it processed, and it sits in Builds as Ready to Submit — but you never added it to the external testing group or sent it to internal testers. The old build expires; testers can’t see the new one.

How to spot it: In TestFlight → your group, check the list of builds attached. If the latest build is missing from the group, attach it.

5. New build awaiting Beta App Review

You uploaded promptly, but the new version’s first build is queued for Beta App Review. The old build expires during the wait, and testers see neither.

How to spot it: New build status is Waiting for Beta App Review. Use internal testing as a stopgap (no review needed), or wait out the review.

Information to collect

  • Upload date of the expired build (for the 90-day math).
  • Version (CFBundleShortVersionString) and build number (CFBundleVersion) of the expired build.
  • Status of any pending builds (Processing, Waiting for Beta App Review, Ready to Submit).
  • Group attachment for both the expired and any pending builds.
  • Tester complaint timestamps if you need to communicate fix timing.

Shortest path to fix

Step 1: Identify the right “next” build

In App Store Connect → TestFlight → Builds, look for:

  • A processed build at version >= the expired one, with a higher build number.
  • If none exists, you need to upload a new build.

You cannot reactivate the expired build; only replacement works.

Step 2: Build a fresh archive

Each build of the same version needs a unique, higher build number — Apple rejects or silently drops a duplicate CFBundleVersion within the same version train. In Xcode:

  • Bump CFBundleVersion (e.g. 4748) — required because build 47 is already on Apple’s records.
  • Optionally bump CFBundleShortVersionString if this is a real feature update.
  • Product → Clean Build Folder.
  • Product → Archive (with a Generic iOS Device / “Any iOS Device” destination selected).

You need a current Xcode and SDK to archive and upload to App Store Connect — as of June 2026 Apple requires builds made with Xcode 26 / the iOS 26 SDK or later (the floor took effect April 28, 2026). Apple periodically raises this minimum, and older Xcode/SDK builds are rejected at upload.

Or via the command line:

agvtool next-version -all  # bump build number
xcodebuild -workspace Acme.xcworkspace -scheme Acme \
  -archivePath build/Acme.xcarchive archive
xcodebuild -exportArchive -archivePath build/Acme.xcarchive \
  -exportPath build/ipa -exportOptionsPlist exportOptions.plist
# Upload: altool --upload-app still works for App Store / TestFlight,
# but Apple now recommends notarytool-era tooling or the Transporter app.
xcrun altool --upload-app -f build/ipa/Acme.ipa \
  -t ios --apiKey "$ASC_KEY_ID" --apiIssuer "$ASC_ISSUER_ID"

The App Store Connect API key flags (--apiKey / --apiIssuer) are preferred over an Apple-ID password, since app-specific passwords break whenever you rotate them. The free Transporter app (Mac App Store) is the drag-and-drop alternative if altool errors out.

Step 3: Wait for processing

Apple processes the upload before it’s usable — typically 5-30 minutes, occasionally longer during busy periods. Status moves through ProcessingReady to Submit (or Ready to Test once it’s attached and review-cleared).

# Optional: poll the App Store Connect API for processing state
curl -H "Authorization: Bearer $JWT" \
  "https://api.appstoreconnect.apple.com/v1/builds?filter[app]=$APP_ID&sort=-uploadedDate" \
  | jq '.data[0].attributes.processingState'

processingState returns PROCESSING, then VALID when the build is ready.

Step 4: Submit for Beta App Review (external testers only)

The first build of a new version must clear Beta App Review before external testers can install it. A new build number under the same version usually skips review and goes live automatically. Internal testing (up to 100 App Store Connect team members) never requires review.

In App Store Connect → TestFlight → your external group → select the build → Submit for Beta App Review. As of June 2026 Apple reviews roughly 90% of submissions within 24 hours, so this is rarely the bottleneck.

Step 5: Attach to tester groups

Once the build is Ready to Test:

  • TestFlight → your external group → Builds → ”+” → select the new build.
  • TestFlight → Internal Testing → ”+” → select the new build (no review needed, available almost immediately after processing).

Add it to every active group, not just one — a group that didn’t get the new build still shows testers the old, expired one.

Step 6: Notify testers

In TestFlight → your external group, use Notify Testers. This emails the tester list with a deep link to update.

Fill in the What to Test release notes (this is the field testers see in the TestFlight app). Add replacement-specific guidance, e.g. “Please update — the previous build expired and won’t launch anymore.”

How to confirm the fix

  • The expired build’s status stays Expired, but the new build shows Ready to Test or Available.
  • A tester who updates via the TestFlight app sees the new build’s “What to Test” notes.
  • A cold install on a fresh device using the TestFlight invite link installs the new build, not the expired one.
  • The new build’s expiration date (shown in App Store Connect) is exactly 90 days from its upload date.

If it still fails

  1. New build not visible to testers: confirm it’s attached to the right group and shows Ready to Test (not still Waiting for Beta App Review or only Ready to Submit).
  2. Stale TestFlight cache: have testers force-quit and reopen TestFlight, or sign out and back in. Pull-to-refresh on the app’s TestFlight page also helps.
  3. Wrong group: testers in a group that didn’t get the new build attached keep seeing the old (expired) one. Verify each tester’s group membership.
  4. Upload rejected for build number: if altool/Xcode rejects the upload, the new CFBundleVersion isn’t higher than an existing one for that version — bump it again.
  5. Beta review unusually slow on the replacement: see Beta App Review taking too long.

FAQ

Can I extend or reactivate an expired TestFlight build? No. The 90-day limit is fixed and tied to the upload date, with no per-account exception. The only path is uploading a replacement build.

Why can some testers still open the expired build? The binary is cached on-device, so a tester who already opened it may launch it for a short window after expiration. The next time TestFlight refreshes, it blocks the launch with “This beta has expired.” New installs are blocked immediately.

Do I need a brand-new version number, or just a new build number? Just a higher build number is enough to replace an expired build. A new build under the same version usually skips Beta App Review and goes live fastest. Only bump the version (CFBundleShortVersionString) if you’re shipping an actual feature update.

Does a replacement build always go through Beta App Review? Only the first build of a new version does. Subsequent builds of the same version, and all internal-testing builds, skip review and become available right after processing.

How long until testers can install the replacement? Processing is usually 5-30 minutes. If review is required, add up to ~24 hours (most clear faster). Same-version internal builds are usually testable within minutes.

Prevention

  • Set a calendar reminder ~80 days after every upload for any long-running beta cycle.
  • Keep a rotation rhythm: ship a fresh TestFlight build at least every 60 days, even with minimal code changes.
  • Always keep at least one build under 60 days old attached to active external groups.
  • Bump the build number every meaningful test cycle so rolling forward is mechanical.
  • Document your TestFlight rotation in a BETA.md so the responsibility doesn’t sit with one person.

Tags: #Troubleshooting #App Store #App review #TestFlight #Build expired