Skip to content

EAS Build drops iOS entitlements (associated-domains, application-groups) #4162

Description

@olcaneristi

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):

<key>aps-environment</key><string>production</string>
<key>com.apple.developer.associated-domains</key>
<array>
  <string>applinks:REDACTED-1.go.link</string>
  <string>applinks:REDACTED-2.go.link</string>
  <string>applinks:REDACTED-3.adj.st</string>
</array>
<key>com.apple.security.application-groups</key>
<array><string>group.com.example.app</string></array>

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    needs reviewIssue is ready to be reviewed by a maintainer

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions