`--no-auto-testflight-setup` is ignored when the submit profile has no `ascAppId`: `Team (Expo)` is still created and all Admins enrolled (opt-out lost in 22.0.0)

Open Beginner friendly
#4,397 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
78/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
typescript
Domain
cli, mobile-dev

Research direction

Start in packages/eas-cli/src/submit/ios/AppProduce.ts and compare its default app-resolution path with ensureTestFlightSetup.ts and ensureTestFlightGroup.ts. Reproduce the issue with an empty submit profile and --no-auto-testflight-setup, then inspect the existing context plumbing in submit/context.ts. Done means the opt-out prevents group creation and Admin enrollment on both app-resolution paths, including callers from commands/go.ts.

Written by the indexing model from the issue text.

Description

Build/Submit details page URL

No response

Summary

eas submit -p ios --no-auto-testflight-setup still creates the internal TestFlight group Team (Expo) and adds every Admin on the Apple team to it as a tester, whenever the submit profile has no ascAppId. The flag is only honoured on the ascAppId code path; the default path (app resolved by bundle identifier through ensureAppStoreConnectAppExistsAsync) calls the group setup unconditionally.

Expected: --no-auto-testflight-setup disables the group creation and the tester enrolment on every path, as its description says ("Set up an internal TestFlight group for the app (iOS only)", allowNo: true). On a team where the Admins are not the testers, enrolling them without being asked is a change to the team's TestFlight configuration that the user explicitly opted out of.

Managed or bare?

Managed (continuous native generation; ios/ and android/ are gitignored prebuild output, which is why expo-env-info prints Expo Workflow: bare below).

Environment

eas-cli/24.0.0 darwin-arm64 node-v20.19.4 (global install via bun; expo-env-info does not see the bun global registry, so its npmGlobalPackages line is corrected by hand below).

expo-env-info 2.1.0 environment info:
    System:
      OS: macOS 26.5.2
      Shell: 5.9 - /bin/zsh
    Binaries:
      Node: 20.19.4 - ~/.nvm/versions/node/v20.19.4/bin/node
      Yarn: 1.22.22 - ~/.nvm/versions/node/v20.19.4/bin/yarn
      npm: 10.8.2 - ~/.nvm/versions/node/v20.19.4/bin/npm
    Managers:
      CocoaPods: 1.16.2 - /opt/homebrew/bin/pod
    SDKs:
      iOS SDK:
        Platforms: DriverKit 25.5, iOS 26.5, macOS 26.5, tvOS 26.5, visionOS 26.5, watchOS 26.5
    IDEs:
      Android Studio: 2025.2 AI-252.25557.131.2521.14344949
      Xcode: 26.5/17F42 - /usr/bin/xcodebuild
    npmPackages:
      expo: ~57.0.20 => 57.0.20
      expo-router: ~57.0.19 => 57.0.19
      react: 19.2.3 => 19.2.3
      react-dom: 19.2.3 => 19.2.3
      react-native: 0.86.3 => 0.86.3
      react-native-web: ~0.21.0 => 0.21.2
    npmGlobalPackages:
      eas-cli: 24.0.0 (bun global install)
    Expo Workflow: bare   <- see above; the project is managed
Error output

No error. After a successful eas submit --platform ios --profile <profile> (submit profile {}, no ascAppId, key on the EAS credentials service), App Store Connect > TestFlight shows a new internal group Team (Expo) with automatic distribution on and every Admin of the team enrolled as a tester. That run did not pass --no-auto-testflight-setup; that the flag would not have changed the outcome on this path is established from the source below, and the steps to observe it are in the repro section. (The messages for this step are TestFlight group created: Team (Expo) and TestFlight access enabled for: ..., from ensureTestFlightGroup.ts.)

Where it happens (eas-cli main)

packages/eas-cli/src/submit/ios/IosSubmitCommand.ts, resolveAscAppIdentifierAsync, has two branches:

  • With ascAppId in the profile (L175): ensureTestFlightSetupForExistingAppAsync(this.ctx, ascAppId). That function checks the flag first (packages/eas-cli/src/submit/ios/ensureTestFlightSetup.ts L28: if (!ctx.autoTestFlightSetup) return;). Correct.
  • Without ascAppId (L194): ensureAppStoreConnectAppExistsAsync(this.ctx) in packages/eas-cli/src/submit/ios/AppProduce.ts, which resolves or creates the app and then, at L97, calls ensureTestFlightGroupExistsAsync(app, { nonInteractive }) inside a try/catch. Nothing on this path reads ctx.autoTestFlightSetup.

ensureTestFlightGroupExistsAsync (packages/eas-cli/src/credentials/ios/appstore/ensureTestFlightGroup.ts) then creates the Team (Expo) group with hasAccessToAllBuilds: true when the app has no groups, lists the team's users, filters to UserRole.ADMIN, and bulk-assigns them as beta testers.

The flag is plumbed into SubmissionContext (packages/eas-cli/src/commands/submit.ts L111-L113, L162, L233; submit/context.ts), so ctx.autoTestFlightSetup is available in AppProduce.ts; it is just not consulted there.

How it got here (regression in 22.0.0)
  • 14.6.0, #2839: eas submit starts auto-creating the internal group on the AppProduce path.
  • 15.0.11, #2856: skip when groups already exist, and an opt-out: EAS_NO_AUTO_TESTFLIGHT_SETUP, checked at the top of ensureTestFlightGroupExistsAsync, so it covered every caller.
  • 22.0.0, #4136: adds the ascAppId path and the --[no-]auto-testflight-setup flag, and removes the EAS_NO_AUTO_TESTFLIGHT_SETUP check from ensureTestFlightGroupExistsAsync (diff of #4136, ensureTestFlightGroup.ts). The flag is read only in the new ensureTestFlightSetupForExistingAppAsync.

So since 22.0.0 the default path has no opt-out at all: the env var is gone and the flag is not read. The 22.0.0 changelog entry ("with --no-auto-testflight-setup to disable it") reads as if the flag disables the behaviour; it disables it on one of the two paths.

Docs

The behaviour is not described anywhere a user reads before their first submit. Submit to the Apple App Store does not mention it. Distribute an iOS app with TestFlight says to create internal groups by hand in App Store Connect and target them with --groups, and does not mention that eas submit will create one and enrol the Admins on its own. The only mention is the flag's one-line description in the CLI reference.

Reproducible demo or steps to reproduce from a blank project
  1. npx create-expo-app repro && cd repro && eas init && eas build:configure. Set ios.bundleIdentifier to a bundle id on your Apple team whose App Store Connect app has no TestFlight groups yet (a fresh app record, or one where you removed the groups). Add "submit": { "production": {} } and do not set ascAppId.
  2. Set up an App Store Connect API key for EAS Submit (eas credentials -p ios).
  3. eas build -p ios --profile production.
  4. eas submit -p ios --profile production --latest --no-auto-testflight-setup.
  5. Observe TestFlight group created: Team (Expo) in the output and the group, with the team's Admins enrolled, in App Store Connect.

Control: add "ascAppId": "<the app's numeric id>" to the submit profile, delete the group, and run step 4 again. No group is created; the flag is honoured on that path.

Suggested fix

Move the check back into ensureTestFlightGroupExistsAsync (where the env var used to be) so every caller respects it (commands/go.ts L45 calls it too), or read ctx.autoTestFlightSetup in createAppStoreConnectAppAsync (AppProduce.ts L97). Restoring EAS_NO_AUTO_TESTFLIGHT_SETUP alongside the flag would also help CI, where a flag has to be threaded through every invocation and an env var does not.

Docs: a sentence in the TestFlight guide saying that the first eas submit creates Team (Expo) and enrols all Admins unless a group already exists or --no-auto-testflight-setup is passed.

The default itself

Beyond the flag bug: as far as we could find, this default is undocumented, and it is an undesirable one. Every other thing eas submit does is scoped to the build it is submitting. This step reaches into the team: it creates a distribution group the user did not ask for, with automatic access to every future build, and enrols people by role rather than by choice, so each Admin gets a TestFlight invitation for an app they may have no part in testing, on the first submit, when whoever is running it is least likely to know a flag exists. Reading the Admin list also needs an Admin-role key, so the step silently depends on the key's role in a way the submission itself does not.

The behaviour the TestFlight guide describes is the right one: the team creates the groups it wants and eas submit --groups targets them. Please consider making the automatic group opt-in (--auto-testflight-setup, default off), or at least asking before creating it in interactive mode; and in either case documenting it in the TestFlight guide, not only as a flag description.

Dominant language
TypeScript
Stars
1.4k
Forks
238
Avg merge
2d 23h
Merged PRs (30d)
87

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from expo/eas-cli

All issues in expo/eas-cli

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.