Your fastlane iOS lane exits before the TestFlight build is testable; which upload_to_testflight options control that wait?
answer
- accepted bytes are not a usable build
- one option decides whether, three decide how
- polling gap versus overall cap
- unbounded waits hold a macOS runner
basics
~10 sUploading an iOS build to TestFlight is not the same as the build being testable: Apple processes it first. Four upload_to_testflight options govern that wait — skip_waiting_for_build_processing, wait_for_uploaded_build, wait_processing_interval and wait_processing_timeout_duration.
solid answer
~40 s`upload_to_testflight` finishes when Apple accepts the bytes; the iOS build is only testable once Apple has **processed** it. `skip_waiting_for_build_processing: true` returns immediately and gives up everything that needs a processed build — distribution to testers and build-level information — in that run. Leaving it false makes the action poll, with `wait_processing_interval` setting the seconds between polls and `wait_processing_timeout_duration` capping the whole wait so a stuck build fails the lane instead of holding a macOS runner. `wait_for_uploaded_build` ties the wait to the build *this* run uploaded rather than whichever is newest, which matters when two branches of the bookbinding order app upload at once. None of this exists on Android: there is no core Android beta action to wait on.
code
ruby · 8 linesupload_to_testflight(
api_key_path: "fastlane/asc_api_key.json",
app_identifier: "com.bindery.bookbindingorders",
changelog: "Nightly build for the bindery floor test.",
wait_for_uploaded_build: true,
wait_processing_interval: 30,
wait_processing_timeout_duration: 1800
)go deeper
Recall that an iOS upload finishing is not the same as testers having the build, and that the waiting behaviour is configured by options on the upload action rather than by sleeping in a script.
Explain what each of the four options changes: whether the action polls at all, which build it watches, how often it asks, and when it gives up and fails the lane.
Show the operational judgment — a fast lane whose green means only that bytes arrived, a gating lane that waits with a bounded timeout, and a runner-capacity argument for keeping them separate.
Own the signalling question: what a green mobile pipeline is allowed to claim, and how you stop a fast internal lane from being read as a release-readiness gate.
## Upload is not availability `upload_to_testflight` — the canonical action behind the `pilot` and `testflight` aliases — finishes when Apple has **accepted the bytes** of an iOS `.ipa`. Acceptance is not availability. Apple then **processes** the build, and only once processing completes can the build be handed to testers or carry build-level information. A lane that returns the moment the transfer ends therefore reports success on a build nobody can install yet, and any later step in the same run that assumes a usable build will fail or quietly do nothing. For the bookbinding order app — an iOS app a bindery uses to take and track custom binding orders — this surfaces as the classic message in the team channel: *CI is green, so where is the build?* ## The four options that control the wait `upload_to_testflight` exposes a small, closed family of options for this, and they do different jobs: - **`skip_waiting_for_build_processing`** — when true, the action returns as soon as the upload is accepted and never polls. It is the fastest lane you can write, and it costs you everything that needs a processed build: distribution to testers and build-level information cannot happen in that run. - **`wait_for_uploaded_build`** — ties the wait to the build *this run* uploaded rather than to whichever build happens to be newest in the account. It matters the moment two branches or two lanes can push builds concurrently. - **`wait_processing_interval`** — the gap, in seconds, between status polls. A short interval gives a tighter feedback loop and more API chatter; a long one is calmer and can overshoot the moment the build became ready. - **`wait_processing_timeout_duration`** — an upper bound on the whole wait. When it is exceeded the action stops waiting and fails, rather than polling until the CI job's own timeout kills it with a far less informative error. The first option decides **whether** you wait; the other three decide **how** you wait. ## Choosing the shape of the lane One beta lane rarely wants a single answer. A workable split for the bookbinding order app: 1. **A fast internal lane** on every merge to the integration branch: upload with `skip_waiting_for_build_processing: true` and let a later job or a human pick the build up. Its success means only *the binary reached Apple*, and the job name should say so. 2. **A release-candidate lane** for the build the bindery's pilot sites will actually install: wait for processing, set `wait_processing_timeout_duration` so the job cannot hang, and attach the changelog and distribute only after the wait returns. 3. **A recovery path** for when processing outlasts the job: distribute the build that already landed in a second run, instead of rebuilding and uploading a fresh build number. ## What waiting costs Waiting is not free. The lane usually holds a **macOS runner** — the scarcest capacity most mobile teams have — for the whole of a processing step whose duration is outside your control and varies with load. Three consequences worth stating out loud: - The wait's duration is **not a property of your code**, so writing a fixed number into a pipeline SLA is wrong from the start. - Without `wait_processing_timeout_duration`, one stuck build can occupy a runner for the job's full limit and stall every other iOS job queued behind it. - A green lane that skipped the wait is a **weaker signal** than a green lane that waited, and a dashboard that renders them identically is lying to its readers. ## There is no Android half of this The whole option family is Apple-specific, and the divergence is real rather than cosmetic. fastlane ships **no core Android beta-distribution action** at all: the Firebase App Distribution route is a **third-party plugin**, and the core Google Play route is `upload_to_play_store` (`supply`), a store lane aimed at a track and authenticated with a Google service-account JSON key. Neither sits behind Apple's processing queue, so *wait for processing* is not a step an Android beta lane has. An answer that describes one waiting model for both platforms is wrong on its face. ## Diagnosing it after the fact When someone reports a green lane and missing iOS testers, work the list in order: - Check whether `skip_waiting_for_build_processing` was set — in the lane, in an environment file, or as a CI variable that overrides the Fastfile. - Check whether the failure was a **timeout from the wait** rather than an upload error; the two look alike in a truncated log and have opposite fixes. - Check whether the run distributed at all or only uploaded; an upload with no distribution leaves a perfectly good build where no tester will look. - Check whether another branch uploaded at the same time, which is exactly the ambiguity `wait_for_uploaded_build` exists to remove.
- Why does a lane that waits for iOS build processing cost more than one that does not?It holds the CI runner — usually a macOS one, the scarcest kind — for the whole of Apple's processing, whose duration you do not control. Waiting is right for a release-candidate lane that must gate on a testable build, and wasteful for a nightly upload nobody blocks on. `wait_processing_timeout_duration` stops a stuck build from holding the runner indefinitely.
- When would you set `wait_for_uploaded_build` on the bookbinding order app's iOS lane?When more than one branch or lane can upload builds at the same time. It ties the wait to the build this run uploaded rather than to whichever build is newest in the account, so a concurrent upload from another branch cannot make the lane report success against someone else's binary.
Uploading is dropping a roll of film at the lab: the counter takes it in seconds, but nobody sees prints until developing finishes. Skipping the wait is leaving the counter without asking whether the prints exist yet.
saying these in an interview costs you the question
- Treating a finished upload as a testable iOS build
- Setting skip_waiting_for_build_processing and still expecting distribution
- Confusing wait_processing_interval with an overall timeout
- Leaving the wait unbounded so a stuck build holds the runner
- Assuming an Android beta lane has the same processing wait