Skip to content

Managed tvOS builds wrongly regenerate credentials since eas-cli 20.2.0 – valid tvOS App Store profile reported "does not exist" #3905

Description

@plindberg

Summary

Since eas-cli 20.2.0 (#3805), non-interactive iOS builds of a managed tvOS app fail at the credentials step. The build now authenticates with the submission App Store Connect API key and validates the provisioning profile against Apple; because a managed project has no native target at credential-resolution time, getApplePlatformFromTarget defaults to iOS, so the profile list is filtered to IOS_APP_STORE and the valid TVOS_APP_STORE profile is reported as does not exist in Apple Developer Portal. EAS then tries to regenerate it and fails. eas-cli ≤ 20.1.0 builds the same project, because when unauthenticated it skips Apple-side validation and reuses the stored tvOS profile.

Managed or bare?

Managed (Expo Workflow: managed; ios/ is gitignored / generated by prebuild). tvOS via react-native-tvos + @react-native-tvos/config-tv, built with EXPO_TV=1.

Environment

expo-env-info 2.0.14 environment info:
  System:
    OS: macOS 26.5.1
  Binaries:
    Node: 22.22.0
    npm: 10.9.4
  npmPackages:
    expo: ~56.0.12 => 56.0.12
    react-native-tvos: 0.85.3-2
    @react-native-tvos/config-tv: 0.1.6
  Expo Workflow: managed

eas-cli: reproduced on 20.2.0–20.4.0; last working version is 20.1.0.

Error output

EXPO_DEBUG=true eas build --platform ios --non-interactive for a managed tvOS app on eas-cli 20.4.0:

✔ Using remote iOS credentials (Expo server)
Distribution Certificate is not validated for non-interactive builds.
Using App Store Connect API Key from EAS credentials service.
- Fetching Apple provisioning profiles
✔ Fetched Apple provisioning profiles
Provisioning profile (id: null) does not exist in Apple Developer Portal
- Fetching Apple provisioning profiles
✔ Fetched Apple provisioning profiles
- Creating Apple provisioning profile
✖ Failed to create Apple provisioning profile
The specified resource does not exist - The path provided does not match a defined resource type.
UnexpectedAppleResponse: The specified resource does not exist - The path provided does not match a defined resource type.
    at async getCertificateBySerialNumberAsync (.../credentials/ios/appstore/distributionCertificate.js)
    at async createProvisioningProfileAsync (.../credentials/ios/appstore/provisioningProfile.js)
    at async CreateProvisioningProfile.provideOrGenerateAsync (.../credentials/ios/actions/CreateProvisioningProfile.js)

The does not exist line is the key symptom, and it appears even when the EAS-stored provisioning profile is a valid, Active TVOS_APP_STORE profile. If a developerPortalIdentifier is stored, the message names it explicitly (Provisioning profile (id: <ACTIVE_TVOS_PROFILE_ID>) does not exist) — i.e. a profile that is present and Active on the Apple Developer Portal is reported missing. The subsequent Creating … / Failed to create is a secondary symptom; the root problem is that validation rejects the valid tvOS profile and forces regeneration.

Root cause (traced at the v20.2.0 tag)

  • actions/SetUpProvisioningProfile.ts L107–108 — for non-interactive builds it now calls tryAuthenticateAppStoreWithEasAscApiKeyAsync (added in [eas-cli] Validate/regenerate/create provisioning profile in non-interactive iOS builds using submission ASC API key when present #3805) before validating, so ctx.appStore.authCtx is set. Pre-20.2.0 there was no auth context.
  • validators/validateProvisioningProfile.ts L32–36 — if (!ctx.appStore.authCtx) { … return true }. Without auth it reused the stored profile; with auth it proceeds to Apple validation.
  • Same file L93–94 — const applePlatform = getApplePlatformFromTarget(target); … ctx.appStore.listProvisioningProfilesAsync(bundleId, applePlatform, …), which filters to resolveProfileType(applePlatform, …) (IOS_APP_STORE for iOS, TVOS_APP_STORE for tvOS).
  • project/ios/target.ts L257–261 — getApplePlatformFromTarget(target) returns getApplePlatformFromSdkRoot(target) ?? getApplePlatformFromDeviceFamily(target) ?? ApplePlatform.IOS. For a managed project, resolveManagedProjectTargetsAsync returns targets without buildSettings (only the bare-project paths set it), so both helpers read target.buildSettings?.SDKROOT / ?.TARGETED_DEVICE_FAMILY as undefined and it defaults to ApplePlatform.IOS (L270 / L295).

Net: a managed tvOS build validates against IOS_APP_STORE profiles, so the TVOS_APP_STORE profile is never matched → does not exist → regenerate.

Suggested fix

Either:

  • (a) derive the Apple platform for managed projects from the app config (e.g. EXPO_TV / @react-native-tvos/config-tv / a tvOS deployment target) instead of defaulting to iOS; or
  • (b) when the stored provisioning profile has a developerPortalIdentifier, match it by id without the platform/type pre-filter.

Reproducible steps (from a fresh managed tvOS project)

  1. A managed Expo (SDK 56) app configured for tvOS with react-native-tvos + @react-native-tvos/config-tv; ios/ not committed.
  2. In EAS credentials for the iOS bundle: a TVOS_APP_STORE provisioning profile on a valid distribution certificate, and an App Store Connect API key configured for submissions.
  3. Run EXPO_TV=1 eas build --platform ios --profile <tvos-profile> --non-interactive on eas-cli ≥ 20.2.0 → fails as above.
  4. Run the same command on eas-cli 20.1.0 → Skipping Provisioning Profile validation on Apple Servers because we aren't authenticated. → reuses the stored tvOS profile → builds successfully.

(A Snack isn't applicable: this is an EAS Build credential-resolution path that requires an Expo account and Apple Developer setup; the steps above are the minimal reproduction. A failing build URL can be provided privately.)

Metadata

Metadata

Assignees

Labels

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions