Build/Submit details page URL
Omitted from the public issue because the build belongs to a private project. I can provide the build URL and server request ID privately to Expo maintainers.
Summary
With uploadSourceMaps: true, an otherwise successful Android EAS Build cannot upload its source map to EAS Observe because the processed Gradle-generated map is 7,836,304 bytes and the server rejects maps at 5 MiB. A production expo export --platform android --source-maps external for the same JavaScript produces a Hermes-composed map that is 5,059,651 bytes after removing sourcesContent, which is below the 5 MiB limit.
Expected: EAS Build uploads an equivalent source map that fits the server limit, supports a compact/compressed representation, or provides a supported way to select/process the map before upload.
Actual: the Android app bundle finishes successfully, but source-map upload fails and EAS Observe errors cannot be symbolicated.
Managed or bare?
Managed / Continuous Native Generation. EAS runs npx expo prebuild --clean; the EAS job reports type: managed.
Environment
Local:
OS: Linux / WSL2
Node: 20.19.5
npm: 10.8.2
eas-cli: 23.2.0
Packages:
expo: 57.0.21
expo-observe: 57.0.20
expo-router: 57.0.20
expo-updates: 57.0.21
react: 19.2.3
react-native: 0.86.3
react-native-reanimated: 4.5.1
react-native-worklets: 0.10.1
EAS Build:
Platform: Android
Profile: preview
Build type: app-bundle
Node: 22.13.0
Image: ubuntu-26.04-jdk-17-ndk-r27b-sdk-57
NODE_ENV: production
BABEL_ENV: production
Expo Doctor:
21/21 checks passed. No issues detected.
Error output
The Gradle build first creates the packager map:
Writing sourcemap output to: <project>/android/app/build/intermediates/sourcemaps/react/release/index.android.bundle.packager.map
During UPLOAD_BUILD_ARTIFACTS, EAS selects the generated map:
Uploading source map: <project>/android/app/build/generated/sourcemaps/react/release/index.android.bundle.map
Source map upload failed
size: 7836304
Unexpected response from server (400):
{"errors":[{"code":"VALIDATION_ERROR","type":"USER","message":"Source map size must be less than 5 MiB.","isTransient":false}]}
The build itself finishes successfully; only source-map upload is reported as a warning.
Reproducible demo or steps to reproduce from a blank project
The exact EAS build URL and request ID can be shared privately with Expo maintainers.
-
Use an Expo SDK 57 managed/CNG app with a sufficiently large native JavaScript graph. The affected build bundled 4,499 modules. The largest dependency is stream-chat-expo@9.3.0, but the failure occurs in EAS source-map upload rather than Stream runtime code.
-
Install expo-observe@57.0.20.
-
Configure an EAS Android profile with production transforms and source-map upload:
{
"build": {
"preview": {
"distribution": "internal",
"uploadSourceMaps": true,
"env": {
"NODE_ENV": "production",
"BABEL_ENV": "production"
},
"android": {
"buildType": "app-bundle"
}
}
}
}
-
Run eas build --platform android --profile preview --clear-cache.
-
Observe the 400 validation error during UPLOAD_BUILD_ARTIFACTS when the stripped map is larger than 5 MiB.
For comparison, generate the Expo CLI production export locally:
NODE_ENV=production BABEL_ENV=production npx expo export \
--platform android \
--source-maps external \
--clear
Parsing the resulting Android Hermes map, deleting only the top-level sourcesContent property, and serializing it with JSON.stringify gives:
Raw Hermes map: 21,277,447 bytes
Without sourcesContent: 5,059,651 bytes (4.83 MiB)
5 MiB server limit: 5,242,880 bytes
The corresponding EAS Gradle-generated upload payload is 7,836,304 bytes (7.47 MiB). Could EAS use the smaller Expo CLI-equivalent Hermes map, further compact the Gradle map, accept gzip transfer/storage, or expose a supported preprocessing/upload path?
Build/Submit details page URL
Omitted from the public issue because the build belongs to a private project. I can provide the build URL and server request ID privately to Expo maintainers.
Summary
With
uploadSourceMaps: true, an otherwise successful Android EAS Build cannot upload its source map to EAS Observe because the processed Gradle-generated map is 7,836,304 bytes and the server rejects maps at 5 MiB. A productionexpo export --platform android --source-maps externalfor the same JavaScript produces a Hermes-composed map that is 5,059,651 bytes after removingsourcesContent, which is below the 5 MiB limit.Expected: EAS Build uploads an equivalent source map that fits the server limit, supports a compact/compressed representation, or provides a supported way to select/process the map before upload.
Actual: the Android app bundle finishes successfully, but source-map upload fails and EAS Observe errors cannot be symbolicated.
Managed or bare?
Managed / Continuous Native Generation. EAS runs
npx expo prebuild --clean; the EAS job reportstype: managed.Environment
Error output
The Gradle build first creates the packager map:
During
UPLOAD_BUILD_ARTIFACTS, EAS selects the generated map:The build itself finishes successfully; only source-map upload is reported as a warning.
Reproducible demo or steps to reproduce from a blank project
The exact EAS build URL and request ID can be shared privately with Expo maintainers.
Use an Expo SDK 57 managed/CNG app with a sufficiently large native JavaScript graph. The affected build bundled 4,499 modules. The largest dependency is
stream-chat-expo@9.3.0, but the failure occurs in EAS source-map upload rather than Stream runtime code.Install
expo-observe@57.0.20.Configure an EAS Android profile with production transforms and source-map upload:
{ "build": { "preview": { "distribution": "internal", "uploadSourceMaps": true, "env": { "NODE_ENV": "production", "BABEL_ENV": "production" }, "android": { "buildType": "app-bundle" } } } }Run
eas build --platform android --profile preview --clear-cache.Observe the 400 validation error during
UPLOAD_BUILD_ARTIFACTSwhen the stripped map is larger than 5 MiB.For comparison, generate the Expo CLI production export locally:
NODE_ENV=production BABEL_ENV=production npx expo export \ --platform android \ --source-maps external \ --clearParsing the resulting Android Hermes map, deleting only the top-level
sourcesContentproperty, and serializing it withJSON.stringifygives:The corresponding EAS Gradle-generated upload payload is 7,836,304 bytes (7.47 MiB). Could EAS use the smaller Expo CLI-equivalent Hermes map, further compact the Gradle map, accept gzip transfer/storage, or expose a supported preprocessing/upload path?