EAS Build drops iOS entitlements (associated-domains, application-groups)
- Dominant language
- TypeScript
- Stars
- 1.4k
- Forks
- 236
- Avg merge
- 3d 1h
- Merged PRs (30d)
- 91
Description
### Build/Submit details page URL
Failing: https://expo.dev/accounts/hayatpay/projects/hayatpay-app/builds/57d2c9f9-935a-41c2-88b9-bde8a32980fa
Passing (same commit): https://expo.dev/accounts/hayatpay/projects/hayatpay-app/builds/b0db91ab-d561-4a14-a58c-8a0cb52092e4
Passing (extension disabled): https://expo.dev/accounts/hayatpay/projects/hayatpay-app/builds/5ae7953e-3d70-4170-a3cc-a0688872dd8a
### Summary
Our iOS builds silently lose **all entitlements on the main app target** in the signed IPA —`com.apple.developer.associated-domains`, `aps-environment` and `com.apple.security.application-groups` are all missing, which breaks Universal Links. The app extension in the same IPA is signed correctly. This setup worked for ~10 months and broke with no change on our side: `app.config.ts`, `eas.json`, `package.json` and every config plugin are byte-identical between our last good build (prod 1.36.0, 2026-07-14) and the first bad one (prod 1.39.0, 2026-07-25) — only JS/TS application code changed in that window. Same `@expo/config-plugins` (10.1.2), same pinned image (`macos-sequoia-15.6-xcode-26.2`).
The entitlements are correct everywhere we can inspect before signing: `expo config --type introspect`, the build log's own "Using app configuration" output, the `.entitlements` file written by `expo prebuild`, `CODE_SIGN_ENTITLEMENTS` in `project.pbxproj`, and the provisioning profile (which grants `associated-domains => "*"`). Disabling the extension plugin — with no other change — makes the main app's entitlements reappear. It is also not deterministic: of 4 builds from the identical commit, 1 was correct and 3 were not.
### Managed or bare?
Managed — ios/ and android/ are gitignored (0 native files in the repo), so EAS runs expo prebuild on every build. Note: expo-env-info reports "bare" only because a local ios/ directory exists on my machine from running prebuild manually.
### Environment
expo-env-info 2.1.0 environment info:
System:
OS: macOS 26.4.1
Shell: 5.9 - /bin/zsh
Binaries:
Node: 24.3.0
Yarn: 1.22.22
npm: 11.4.2
Watchman: 2025.06.30.00
Managers:
CocoaPods: 1.16.2
SDKs:
iOS SDK:
Platforms: DriverKit 25.2, iOS 26.2, macOS 26.2, tvOS 26.2, visionOS 26.2, watchOS 26.2
IDEs:
Android Studio: 2025.3
Xcode: 26.2/17C52
npmGlobalPackages:
eas-cli: 18.6.0
Expo Workflow: bare
expo-doctor: 17/17 checks passed. No issues detected!
Expo SDK: 53.0.0 (expo 53.0.27, react-native 0.79.6)
@expo/config-plugins: 10.1.2
eas.json ios image: macos-sequoia-15.6-xcode-26.2
### Error output
No error is emitted — the build succeeds. The failure is silent: entitlements are missing from the signed binary, so Universal Links stop working with no diagnostic. (Identifiers below are redacted; happy to share them privately.)
Signed **main app** in the failing build — only the keys EAS/Xcode adds itself:
$ codesign -d --entitlements - Payload/MyApp.app
[Dict]
[Key] application-identifier
[Key] beta-reports-active
[Key] com.apple.developer.team-identifier
[Key] get-task-allow
Signed **extension** in the very same IPA — its entitlement is applied correctly:
$ codesign -d --entitlements - Payload/MyApp.app/PlugIns/MyExtension.appex
[Dict]
[Key] application-identifier
[Key] beta-reports-active
[Key] com.apple.developer.team-identifier
[Key] com.apple.security.application-groups <-- present here
[Key] get-task-allow
Main app `.entitlements` written by `expo prebuild` before the build (correct):
aps-environmentproduction
com.apple.developer.associated-domains
applinks:REDACTED-1.go.link
applinks:REDACTED-2.go.link
applinks:REDACTED-3.adj.st
com.apple.security.application-groups
group.com.example.app
For reference, the same build with the extension plugin disabled produces a main app signed with `associated-domains`, `aps-environment` and `application-groups` all present.
### Reproducible demo or steps to reproduce from a blank project
I don't have a blank-project repro, and I want to be upfront that the extension target is created by a project-local config plugin — so this could still be our bug. But the strongest argument against that is that **we changed nothing**: that plugin was last modified 2025-10-06, and `app.config.ts`, `eas.json`, `package.json` and every plugin file are byte-identical (verified with `git diff`) between our last good build (2026-07-14) and the first bad one (2026-07-25). Only JS/TS application code changed in that window. The same plugin had been producing correctly signed builds for ~10 months.
- env vars — the build log's own "Using app configuration" shows the correct values
- provisioning profile — grants `associated-domains: "*"` and both app groups; the log shows the expected profile UUID being used
- regenerating credentials from scratch
- `expo` / `@expo/config-plugins` versions — 10.1.2 in both passing and failing builds
- the iOS build image — pinned to `macos-sequoia-15.6-xcode-26.2` throughout
- duplicate or mistyped targets in `project.pbxproj` — verified 2 targets with correct product types, and `CODE_SIGN_ENTITLEMENTS` pointing at the right file for each
- local `expo prebuild --clean` output — always correct, and `ios/` is gitignored so EAS prebuilds from scratch on every build
Happy to run any diagnostic command against a build, or share the redacted identifiers privately.
Contributor guide
Research direction
Start by comparing the passing and failing EAS build logs, expo prebuild output, and signed IPA entitlements. Inspect the project-local extension config plugin alongside app.config.ts, eas.json, package.json, and the generated project settings. Done means identifying why the main app target loses entitlements and verifying with codesign that a fix preserves them while the extension remains correct.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- react-native, typescript
- Domain
- build-system, cli, devops, mobile
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 42/100