Build/Submit details page URL
Omitted to avoid publishing account and project identifiers. I can provide the build URL privately to Expo maintainers if needed.
Summary
When an iOS bundle ID already has App Group A linked and the app requires both A and B, EAS CLI sends only B in the capability relationship update. A is then removed, leaving the provisioning profile unable to satisfy the app's entitlements; repeating credential setup can alternate which group is missing.
Expected: adding B preserves A, producing a profile containing both configured groups. If both groups are already linked, no update should be necessary.
Managed or bare?
Managed / Continuous Native Generation: ios/ and android/ are gitignored. The app includes local Expo modules and generated notification and sharing extensions.
Environment
Observed with EAS CLI 23.2.0. I also inspected the published 24.7.0 package: its capabilityIdentifiers.js implementation is byte-for-byte identical. I have not run a complete cloud build with 24.7.0.
The same logic is present on upstream main at commit 30a3924f43b31c9f6d03a09d40396341e6225d32.
This checkout shares node_modules with another worktree. The diagnostic output below includes duplicate-module warnings and other failed checks; I am including it for completeness. The function-level reproduction below isolates EAS CLI's generated relationship update from the app's native build.
npx expo-env-info
expo-env-info 2.1.0 environment info:
System:
OS: macOS 15.7.7
Shell: 5.9 - /bin/zsh
Binaries:
Node: 26.8.2 - /opt/homebrew/bin/node
npm: 11.19.1 - /opt/homebrew/bin/npm
Managers:
CocoaPods: 1.17.0 - /opt/homebrew/bin/pod
SDKs:
iOS SDK:
Platforms: DriverKit 25.2, iOS 26.2, macOS 26.2, tvOS 26.2, visionOS 26.2, watchOS 26.2
IDEs:
Xcode: 26.3/17C529 - /usr/bin/xcodebuild
npmPackages:
expo: 57.0.20 => 57.0.20
expo-router: 57.0.19 => 57.0.19
expo-updates: ~57.0.23 => 57.0.21
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.2 => 0.21.2
npmGlobalPackages:
eas-cli: 23.2.0
Expo Workflow: managed
npx expo-doctor
Running 21 checks on your project...
15/21 checks passed. 6 checks failed. Possible issues detected:
Use the --verbose flag to see more details about passed checks.
✖ Check package.json for common issues
The following scripts in package.json conflict with the contents of node_modules/.bin: electron, tauri.
Advice:
Update your package.json to remove conflicts.
✖ Check Expo config (app.json/ app.config.js) schema
Errors validating fields in <project>/app.json:
should NOT have additional property 'newArchEnabled'.
Field: ios - should NOT have additional property 'jsEngine'.
Field: ios - should NOT have additional property 'newArchEnabled'.
Advice:
Resolve schema errors in your app config. Learn more: https://docs.expo.dev/workflow/configuration/
✖ Check dependencies for packages that should not be installed directly
The package "expo-modules-core" should not be installed directly in your project. You should instead use the exported API from the expo package.
Advice:
Remove these packages from your package.json.
✖ Check that no duplicate dependencies are installed
Your project contains duplicate native module dependencies, which should be de-duplicated.
Native builds may only contain one version of any given native module, and having multiple versions of a single Native module installed may lead to unexpected build errors.
[Project-specific module names and paths redacted. Doctor reported duplicate copies of five local native modules because this checkout shares node_modules with another worktree.]
Advice:
Deduplicate native dependencies.
Resolve your dependency issues and deduplicate your dependencies. Learn more: https://expo.fyi/resolving-dependency-issues
✖ Validate packages against React Native Directory package metadata
The following issues were found when validating your dependencies against React Native Directory:
Untested on New Architecture: @nozbe/watermelondb, @simform_solutions/react-native-audio-waveform, expo-pretext, react-native-file-viewer, react-native-nitro-fetch
Unmaintained: react-native-file-viewer
No metadata available: [dependency list redacted; includes project-specific native modules]
Advice:
Use libraries that are actively maintained and support the New Architecture. Find alternative libraries with https://reactnative.directory.
Add packages to expo.doctor.reactNativeDirectoryCheck.exclude in package.json to selectively skip validations, if the warning is not relevant.
Update React Native Directory to include metadata for unknown packages. Alternatively, set expo.doctor.reactNativeDirectoryCheck.listUnknownPackages in package.json to false to skip warnings about packages with no metadata, if the warning is not relevant.
✖ Check that packages match versions required by installed Expo SDK
❗ Major version mismatches
package expected found
react-native-gesture-handler ~2.32.0 3.2.1
🔧 Patch version mismatches
package expected found
@expo/ui ~57.0.19 57.0.16
expo ~57.0.24 57.0.20
expo-application ~57.0.3 57.0.2
expo-asset ~57.0.18 57.0.16
expo-audio ~57.0.5 57.0.4
expo-blur ~57.0.3 57.0.2
expo-build-properties ~57.0.21 57.0.17
expo-camera ~57.0.5 57.0.4
expo-constants ~57.0.19 57.0.17
expo-dev-client ~57.0.19 57.0.18
expo-device ~57.0.2 57.0.1
expo-document-picker ~57.0.2 57.0.1
expo-file-system ~57.0.7 57.0.6
expo-font ~57.0.4 57.0.3
expo-haptics ~57.0.3 57.0.2
expo-image ~57.0.5 57.0.4
expo-image-manipulator ~57.0.19 57.0.16
expo-image-picker ~57.0.19 57.0.16
expo-keep-awake ~57.0.2 57.0.1
expo-linear-gradient ~57.0.2 57.0.1
expo-linking ~57.0.10 57.0.9
expo-localization ~57.0.2 57.0.1
expo-maps ~57.0.3 57.0.2
expo-media-library ~57.0.5 57.0.4
expo-modules-core ~57.0.18 57.0.16
expo-notifications ~57.0.20 57.0.17
expo-observe ~57.0.23 57.0.19
expo-router ~57.0.22 57.0.19
expo-secure-store ~57.0.4 57.0.3
expo-sharing ~57.0.21 57.0.18
expo-splash-screen ~57.0.9 57.0.8
expo-symbols ~57.0.3 57.0.2
expo-system-ui ~57.0.4 57.0.3
expo-task-manager ~57.0.19 57.0.16
expo-updates ~57.0.23 57.0.21
expo-video ~57.0.4 57.0.3
expo-web-browser ~57.0.3 57.0.2
Changelogs:
- expo-application → https://github.com/expo/expo/blob/sdk-57/packages/expo-application/CHANGELOG.md
- expo-asset → https://github.com/expo/expo/blob/sdk-57/packages/expo-asset/CHANGELOG.md
- expo-audio → https://github.com/expo/expo/blob/sdk-57/packages/expo-audio/CHANGELOG.md
- expo-blur → https://github.com/expo/expo/blob/sdk-57/packages/expo-blur/CHANGELOG.md
- expo-build-properties → https://github.com/expo/expo/blob/sdk-57/packages/expo-build-properties/CHANGELOG.md
- expo-camera → https://github.com/expo/expo/blob/sdk-57/packages/expo-camera/CHANGELOG.md
- expo-constants → https://github.com/expo/expo/blob/sdk-57/packages/expo-constants/CHANGELOG.md
- expo-dev-client → https://github.com/expo/expo/blob/sdk-57/packages/expo-dev-client/CHANGELOG.md
- expo-device → https://github.com/expo/expo/blob/sdk-57/packages/expo-device/CHANGELOG.md
- expo-document-picker → https://github.com/expo/expo/blob/sdk-57/packages/expo-document-picker/CHANGELOG.md
- expo-file-system → https://github.com/expo/expo/blob/sdk-57/packages/expo-file-system/CHANGELOG.md
- expo-font → https://github.com/expo/expo/blob/sdk-57/packages/expo-font/CHANGELOG.md
- expo-haptics → https://github.com/expo/expo/blob/sdk-57/packages/expo-haptics/CHANGELOG.md
- expo-image → https://github.com/expo/expo/blob/sdk-57/packages/expo-image/CHANGELOG.md
- expo-image-manipulator → https://github.com/expo/expo/blob/sdk-57/packages/expo-image-manipulator/CHANGELOG.md
- expo-image-picker → https://github.com/expo/expo/blob/sdk-57/packages/expo-image-picker/CHANGELOG.md
- expo-keep-awake → https://github.com/expo/expo/blob/sdk-57/packages/expo-keep-awake/CHANGELOG.md
- expo-linear-gradient → https://github.com/expo/expo/blob/sdk-57/packages/expo-linear-gradient/CHANGELOG.md
- expo-linking → https://github.com/expo/expo/blob/sdk-57/packages/expo-linking/CHANGELOG.md
- expo-localization → https://github.com/expo/expo/blob/sdk-57/packages/expo-localization/CHANGELOG.md
- expo-maps → https://github.com/expo/expo/blob/sdk-57/packages/expo-maps/CHANGELOG.md
- expo-media-library → https://github.com/expo/expo/blob/sdk-57/packages/expo-media-library/CHANGELOG.md
- expo-modules-core → https://github.com/expo/expo/blob/sdk-57/packages/expo-modules-core/CHANGELOG.md
- expo-notifications → https://github.com/expo/expo/blob/sdk-57/packages/expo-notifications/CHANGELOG.md
- expo-observe → https://github.com/expo/expo/blob/sdk-57/packages/expo-observe/CHANGELOG.md
- expo-router → https://github.com/expo/expo/blob/sdk-57/packages/expo-router/CHANGELOG.md
- expo-secure-store → https://github.com/expo/expo/blob/sdk-57/packages/expo-secure-store/CHANGELOG.md
- expo-sharing → https://github.com/expo/expo/blob/sdk-57/packages/expo-sharing/CHANGELOG.md
- expo-splash-screen → https://github.com/expo/expo/blob/sdk-57/packages/expo-splash-screen/CHANGELOG.md
- expo-symbols → https://github.com/expo/expo/blob/sdk-57/packages/expo-symbols/CHANGELOG.md
- expo-system-ui → https://github.com/expo/expo/blob/sdk-57/packages/expo-system-ui/CHANGELOG.md
- expo-task-manager → https://github.com/expo/expo/blob/sdk-57/packages/expo-task-manager/CHANGELOG.md
- expo-updates → https://github.com/expo/expo/blob/sdk-57/packages/expo-updates/CHANGELOG.md
- expo-video → https://github.com/expo/expo/blob/sdk-57/packages/expo-video/CHANGELOG.md
- expo-web-browser → https://github.com/expo/expo/blob/sdk-57/packages/expo-web-browser/CHANGELOG.md
38 packages out of date.
Advice:
Use 'npx expo install --check' to review and upgrade your dependencies.
To ignore specific packages, add them to "expo.install.exclude" in package.json. Learn more: https://expo.fyi/dependency-validation
6 checks failed, indicating possible issues with the project.
Error output
Provisioning profile "*[expo] com.example.app AdHoc <timestamp>" doesn't support the group.com.example.app App Group.
Provisioning profile "*[expo] com.example.app AdHoc <timestamp>" doesn't match the entitlements file's value for the com.apple.security.application-groups entitlement.
The resolved Expo configuration and generated entitlements both require:
{
"com.apple.security.application-groups": [
"group.com.example.app.notifications",
"group.com.example.app"
]
}
Credential setup logged Linked: group.com.example.app and regenerated the profile. The following build logged Linked: group.com.example.app.notifications, regenerated it again, and failed with the same missing-sharing-group error.
Reproducible demo or steps to reproduce from a blank project
The smallest confirmed reproduction is at the capability-sync function boundary:
- Configure two App Group identifiers, A and B.
- Mock Apple's group inventory to return both existing identifiers.
- Mock the bundle's current App Group relationships to contain only A.
- Call
syncCapabilityIdentifiersForEntitlementsAsync with entitlements requiring [A, B].
- Inspect the argument to
bundleId.updateBundleIdCapabilityAsync.
Actual relationship update: [B]. Expected relationship update: [A, B].
This was verified by executing the published function with mocked Apple dependencies. A small change that includes all configured identifiers in the update passes this case and preserves the no-op when both groups are already linked.
Suggested minimal-app reproduction, not yet executed end to end in a fresh project:
- Create a blank Expo app, initialize EAS, and configure an iOS bundle ID under an Apple Developer team.
- Set
expo.ios.entitlements["com.apple.security.application-groups"] to ["group.<your-bundle-id>.a"].
- Configure an internal development build and run
eas credentials:configure-build --platform ios --profile development, logging in to Apple, to link A and create its profile.
- Add
"group.<your-bundle-id>.b" to the array, retaining A. B can be registered beforehand in the same Apple team.
- Run the same credential command again and inspect the bundle's App Group associations or decode the regenerated provisioning profile.
- Both groups should remain linked. With the faulty update, A is omitted. A subsequent credential sync may restore A while dropping B.
Suspected cause and verified workaround
In capabilityIdentifiers.ts, identifiers that are already linked are omitted from capabilityIdOpaqueIds. That array is then sent as the complete relationship update.
The change in #3615 appears relevant: it introduced this already-linked check.
I temporarily changed the CLI to include every configured identifier in the relationship payload, while only issuing an update when a configured identifier was missing. After regenerating the profile, I downloaded it from EAS and decoded it: it contained both required App Groups and the production APNs entitlement. This verifies the profile repair; I am not claiming a successful cloud build from that check alone.
A potential fix is to keep the full desired relationship list separate from the list of identifiers newly linked for logging. Regression coverage should include an already-linked group plus an existing unlinked group, an already-linked group plus a newly created group, and the all-already-linked no-op.
Build/Submit details page URL
Omitted to avoid publishing account and project identifiers. I can provide the build URL privately to Expo maintainers if needed.
Summary
When an iOS bundle ID already has App Group A linked and the app requires both A and B, EAS CLI sends only B in the capability relationship update. A is then removed, leaving the provisioning profile unable to satisfy the app's entitlements; repeating credential setup can alternate which group is missing.
Expected: adding B preserves A, producing a profile containing both configured groups. If both groups are already linked, no update should be necessary.
Managed or bare?
Managed / Continuous Native Generation:
ios/andandroid/are gitignored. The app includes local Expo modules and generated notification and sharing extensions.Environment
Observed with EAS CLI 23.2.0. I also inspected the published 24.7.0 package: its
capabilityIdentifiers.jsimplementation is byte-for-byte identical. I have not run a complete cloud build with 24.7.0.The same logic is present on upstream main at commit
30a3924f43b31c9f6d03a09d40396341e6225d32.This checkout shares
node_moduleswith another worktree. The diagnostic output below includes duplicate-module warnings and other failed checks; I am including it for completeness. The function-level reproduction below isolates EAS CLI's generated relationship update from the app's native build.npx expo-env-info
npx expo-doctor
Error output
The resolved Expo configuration and generated entitlements both require:
{ "com.apple.security.application-groups": [ "group.com.example.app.notifications", "group.com.example.app" ] }Credential setup logged
Linked: group.com.example.appand regenerated the profile. The following build loggedLinked: group.com.example.app.notifications, regenerated it again, and failed with the same missing-sharing-group error.Reproducible demo or steps to reproduce from a blank project
The smallest confirmed reproduction is at the capability-sync function boundary:
syncCapabilityIdentifiersForEntitlementsAsyncwith entitlements requiring[A, B].bundleId.updateBundleIdCapabilityAsync.Actual relationship update:
[B]. Expected relationship update:[A, B].This was verified by executing the published function with mocked Apple dependencies. A small change that includes all configured identifiers in the update passes this case and preserves the no-op when both groups are already linked.
Suggested minimal-app reproduction, not yet executed end to end in a fresh project:
expo.ios.entitlements["com.apple.security.application-groups"]to["group.<your-bundle-id>.a"].eas credentials:configure-build --platform ios --profile development, logging in to Apple, to link A and create its profile."group.<your-bundle-id>.b"to the array, retaining A. B can be registered beforehand in the same Apple team.Suspected cause and verified workaround
In
capabilityIdentifiers.ts, identifiers that are already linked are omitted fromcapabilityIdOpaqueIds. That array is then sent as the complete relationship update.The change in #3615 appears relevant: it introduced this already-linked check.
I temporarily changed the CLI to include every configured identifier in the relationship payload, while only issuing an update when a configured identifier was missing. After regenerating the profile, I downloaded it from EAS and decoded it: it contained both required App Groups and the production APNs entitlement. This verifies the profile repair; I am not claiming a successful cloud build from that check alone.
A potential fix is to keep the full desired relationship list separate from the list of identifiers newly linked for logging. Regression coverage should include an already-linked group plus an existing unlinked group, an already-linked group plus a newly created group, and the all-already-linked no-op.