EAS failure on Android: "Gradle build failed with unknown error"

We are adding an Android build to our existing app so that we can support both devices. When running on EAS, the build fails with an unknown error message.

Build 1: Build Details — 689231b1-ced4-47a1-8339-91a8da6c8b9b — delta — Expo
Build 2: Build Details — 4a77316b-d0fc-4352-89a8-cd6af92c4c94 — delta — Expo

  • I am in a managed workflow, however, we use EAS build to support modules that are not Expo supported.
  • Your eas-cli version: eas-cli/3.9.1 darwin-arm64 node-v16.20.0
  • What you have tried so far:
    • running the command eas build --profile development --platform android from the terminal

eas.json:

{
  "cli": {
    "version": ">= 2.4.1",
    "promptToConfigurePushNotifications": false
  },
  "build": {
    "m1": {
      "ios": {
        "resourceClass": "m-medium"
      }
    },
    "staging": {
      "extends": "m1",
      "node": "16.15.0",
      "yarn": "1.22.5",
      "env": {
        "API_ADDRESS": "ourAPI",
        "LOG_API_ERRORS": "false",
        "ICON": "./src/assets/icon-stage.png",
        "APP_NAME": "Staging LT",
        "BUNDLE_ID": "com.fluidtruck.lt.stage",
        "ENABLE_DEV_FEATURES": "true"
      },
      "ios": {
        "env": {
          "PLATFORM": "ios"
        },
        "image": "default"
      },
      "android": {
        "buildType": "apk"
      }
    },
    "prod": {
      "extends": "m1",
      "node": "16.15.0",
      "yarn": "1.22.5",
      "env": {
        "API_ADDRESS": "ourAPI",
        "LOG_API_ERRORS": "false",
        "ICON": "./src/assets/icon.png",
        "APP_NAME": "LT App",
        "BUNDLE_ID": "com.fluidtruck.lt"
      },
      "ios": {
        "env": {
          "PLATFORM": "ios"
        },
        "image": "default"
      },
      "android": {
        "buildType": "app-bundle",
        "image": "latest"
      }
    },
    // to release to Test Flight PROD
    "test-flight": {
      "extends": "prod"
    },
    // to release to Test Flight STAGING
    "test-flight:stage": {
      "extends": "staging",
      "env": {
        "LOG_API_ERRORS": "false",
        "APP_NAME": "TF Staging LT"
      }
    },
    // for building test links
    "development-internal": {
      "extends": "staging",
      "distribution": "internal",
      "env": {
        "LOG_API_ERRORS": "true",
        "APP_NAME": "QA Staging LT"
      }
    },
    // for development simulator builds with Native Module packages
    "development": {
      "extends": "staging",
      "distribution": "internal",
      "developmentClient": true,
      "ios": {
        "simulator": true
      },
      "env": {
        "LOG_API_ERRORS": "true",
        "APP_NAME": "Dev Sim"
      }
    },
    // for development device builds with Native Module packages
    "development-device": {
      "extends": "staging",
      "developmentClient": true,
      "distribution": "internal",
      "env": {
        "LOG_API_ERRORS": "true",
        "APP_NAME": "Dev Device"
      }
    }
  }
}

and our app.config

// eslint-disable-next-line @typescript-eslint/no-var-requires
require('dotenv').config();

const bundleIdentifier = process.env.BUNDLE_ID || 'com.fluidtruck.lt.stage';

module.exports = {
  name: process.env.APP_NAME || 'Fluid LT App',
  slug: 'delta',
  owner: 'fluidtruck',
  scheme: 'fluidlt',
  version: '1.6.5', // Only change this if a true version bump is needed.  Apple reviews take longer if you change this field
  orientation: 'portrait',
  userInterfaceStyle: 'automatic',
  icon: process.env.ICON || './src/assets/delta.png',
  privacy: 'unlisted',
  plugins: [
    'newrelic-react-native-agent',
    [
      'react-native-vision-camera',
      {
        cameraPermissionText: 'LT App needs access to your Camera.',
        enableMicrophonePermission: true,
        microphonePermissionText: 'LT App needs access to your Microphone.',
      },
    ],
    'react-native-compressor',
    [
      'expo-image-picker',
      {
        photosPermission: 'This app accesses your photos to let you upload from your library.',
      },
    ],
  ],
  splash: {
    image: './src/assets/splash.png',
    resizeMode: 'contain',
    backgroundColor: '#ffffff',
  },
  updates: {
    fallbackToCacheTimeout: 0,
  },
  assetBundlePatterns: ['./src/assets/**/*.png', './src/assets/icons/**/*.svg'],
  ios: {
    bundleIdentifier,
    buildNumber: '1.6.11',
    infoPlist: {
      NSCameraUsageDescription: 'This app uses the camera to take pictures & video.',
      NSMicrophoneUsageDescription: 'This app may use your microphone.',
      LSApplicationQueriesSchemes: ['comgooglemaps', 'waze'],
    },
  },
  android: {
    package: bundleIdentifier,
  },
  web: {
    favicon: './src/assets/favicon.png',
  },
  userInterfaceStyle: 'automatic',
  extra: {
    api: process.env.API_ADDRESS,
    bundleIdentifier: bundleIdentifier,
    log_api_errors: process.env.LOG_API_ERRORS,
    newrelic_prod: process.env.NEW_RELIC_PROD,
    newrelic_stage: process.env.NEW_RELIC_STAGE,
    ENABLE_DEV_FEATURES: process.env.NODE_ENV === 'development' || process.env.ENABLE_DEV_FEATURES,
    eas: {
      projectId: 'ourID',
    },
  },
};

The error in the EAS logs are very vague for me:

Task :app:mergeProjectDexDebug
FAILED
[stderr] ERROR:/home/expo/workingdir/build/android/app/build/intermediates/mixed_scope_dex_archive/debug/out/cbdbd1fce5fa54770dcc0ed6b494682f30c191323ef4a22ce4760e1c895cf9e5_0.jar: D8: Type com.swmansion.reanimated.BuildConfig is defined multiple times: /home/expo/workingdir/build/android/app/build/intermediates/mixed_scope_dex_archive/debug/out/cbdbd1fce5fa54770dcc0ed6b494682f30c191323ef4a22ce4760e1c895cf9e5_0.jar:classes.dex, /home/expo/workingdir/build/android/app/build/intermediates/mixed_scope_dex_archive/debug/out/e0f9dd988ffbb736b7374aafaee19791124833e5a405f1350c7c84d63deea972_0.jar:classes.dex

Since this error I have tried:

  1. Fixing expo-doctor warnings, by downgrading react-native-maps (see this build). This is not the problem and we have a 2nd project in a separate repo using newer version.
  2. Running npx expo prebuild locally. It successfully compiles and generates ios and android directories. However, I get an error when trying to run npx expo run:android:

Starting a Gradle Daemon, 1 stopped Daemon could not be reused, use --status for details
Configuration on demand is an incubating feature.
Task :react-native-gradle-plugin:compileKotlin FAILED
‘compileJava’ task (current target is 1.8) and ‘compileKotlin’ task (current target is 11) jvm target compatibility should be set to the same Java version
FAILURE: Build failed with an exception.

  • What went wrong:
    • Execution failed for task ‘:react-native-gradle-plugin:compileKotlin’.
      Failed to query the value of task ‘:react-native-gradle-plugin:compileKotlin’ property ‘compilerRunner$kotlin_gradle_plugin’.
      Kotlin could not find the required JDK tools in the Java installation. Make sure Kotlin compilation is running on a JDK, not JRE.
  • Try:
    • Run with –stacktrace option to get the stack trace.
    • Run with –info or –debug option to get more log output.
    • Run with –scan to get full insights.

note: cannot run those flags since it’s a expo command

What is the best next step?

Hi @lucksp

Assuming you have not made any changes to the stuff under the android directory, you should delete it or move it out of the way. If you do that does it make a difference?

ios & android folders are not submitted to EAS, this does not have any change

Do you mean you have added them to .gitignore? OK.

Can you post your dependencies and devDependencies from package.json?

@wodin , yes those are in my gitignore.

Here is package.json:

{
  "main": "node_modules/expo/AppEntry.js",
  "name": "lieutenant_app",
  "version": "1.6.11",
  "private": true,
  "prettier": "@fluidtruck/prettier",
  "scripts": { ... },
  "dependencies": {
    "@fluidtruck/mobile": "^1.16.6",
    "@fluidtruck/mobile-icons": "^1.16.6",
    "@gorhom/bottom-sheet": "^4.4.5",
    "@react-native-async-storage/async-storage": "~1.17.3",
    "@react-native-community/masked-view": "0.1.10",
    "@react-native-community/netinfo": "9.3.0",
    "@react-navigation/drawer": "^6.5.7",
    "@react-navigation/native": "^6.1.6",
    "@react-navigation/native-stack": "^6.7.0",
    "@react-navigation/stack": "^6.3.16",
    "@rneui/base": "github:react-native-elements/react-native-elements#base",
    "@rneui/themed": "github:react-native-elements/react-native-elements#themed",
    "@testing-library/react-native": "^9.0.0",
    "base-64": "^1.0.0",
    "dotenv": "^16.0.0",
    "expo": "~46.0.21",
    "expo-analytics-amplitude": "~11.3.0",
    "expo-application": "~4.2.2",
    "expo-asset": "~8.6.3",
    "expo-av": "~12.0.4",
    "expo-blur": "~11.2.0",
    "expo-clipboard": "~3.1.0",
    "expo-constants": "~13.2.4",
    "expo-dev-client": "~1.3.1",
    "expo-device": "~4.3.0",
    "expo-image-manipulator": "~10.4.0",
    "expo-image-picker": "~13.3.1",
    "expo-linking": "~3.2.4",
    "expo-localization": "~13.1.0",
    "expo-location": "~14.3.0",
    "expo-media-library": "~14.2.0",
    "expo-secure-store": "~11.3.0",
    "expo-system-ui": "~1.3.0",
    "expo-updates": "~0.14.7",
    "geolib": "^3.3.1",
    "husky": "^6.0.0",
    "i18next": "20.2.1",
    "immer": "^9.0.16",
    "json-autotranslate": "1.9.1",
    "lottie-react-native": "5.1.3",
    "moment": "^2.29.1",
    "moment-timezone": "^0.5.33",
    "newrelic-react-native-agent": "^1.0.1",
    "react": "18.0.0",
    "react-dom": "18.0.0",
    "react-hook-form": "^7.25.3",
    "react-i18next": "^11.15.3",
    "react-native": "0.69.9",
    "react-native-compressor": "^1.6.1",
    "react-native-date-picker": "^4.2.11",
    "react-native-element-dropdown": "^1.8.8",
    "react-native-error-boundary": "^1.2.2",
    "react-native-gesture-handler": "~2.5.0",
    "react-native-google-places-autocomplete": "^2.4.1",
    "react-native-keyboard-aware-scrollview": "^2.1.0",
    "react-native-map-clustering": "^3.4.2",
    "react-native-map-link": "^2.10.2",
    "react-native-maps": "1.3.2",
    "react-native-mask-text": "^0.7.0",
    "react-native-reanimated": "~2.9.1",
    "react-native-safe-area-context": "4.3.1",
    "react-native-screens": "~3.15.0",
    "react-native-svg": "12.3.0",
    "react-native-svg-transformer": "^1.0.0",
    "react-native-vision-camera": "^2.15.4",
    "swr": "^1.3.0",
    "use-immer": "^0.7.0"
  },
  "devDependencies": {
    "@babel/core": "^7.17.0",
    "@babel/plugin-proposal-export-namespace-from": "^7.18.9",
    "@babel/preset-typescript": "^7.16.7",
    "@fluidtruck/prettier": "^1.33.0",
    "@testing-library/jest-dom": "^5.16.2",
    "@testing-library/jest-native": "^4.0.4",
    "@testing-library/react": "^12.1.2",
    "@testing-library/react-hooks": "^7.0.2",
    "@types/base-64": "^1.0.0",
    "@types/jest": "^27.4.0",
    "@types/node": "^17.0.14",
    "@types/react-native-dotenv": "^0.2.0",
    "@typescript-eslint/eslint-plugin": "^5.10.2",
    "@typescript-eslint/parser": "^5.10.2",
    "cross-fetch": "^3.1.5",
    "eslint": "^8.8.0",
    "eslint-import-resolver-typescript": "^2.5.0",
    "eslint-plugin-import": "^2.25.4",
    "eslint-plugin-jest": "^26.0.0",
    "eslint-plugin-react": "^7.28.0",
    "eslint-plugin-react-hooks": "^4.2.0",
    "eslint-plugin-react-native": "^4.0.0",
    "eslint-plugin-simple-import-sort": "^7.0.0",
    "jest": "^27.4.7",
    "jest-expo": "^44.0.1",
    "lint-staged": "^13.0.3",
    "msw": "^0.47.2",
    "prettier": "^2.7.1",
    "react-test-renderer": "18.0.0",
    "ts-node": "^10.4.0",
    "ts-unused-exports": "^7.0.3",
    "typescript": "^4.5.5"
  },
  "resolutions": {
    "@jest/create-cache-key-function": "^27.0.2",
    "**/react-native-maps": "^1.3.2"  // this is the outstanding item in expo-doctor, but i tested downgrading to SDK 46 suggested version, with no difference
  }
}

I don’t see anything obviously wrong with your dependencies.

There are some apparently private dependencies, so can’t test thoroughly, but I tried with the rest.

This is deprecated. You should switch to @react-native-masked-view/masked-view.

If I try to build a test app with your dependencies (sans the private ones) I get the same error. Since it seems to have something to do with Reanimated, I got rid of all the dependencies that seemed unlikely to have anything to do with that. Unfortunately then it builds.

So I started adding things back until I had added back everything except the dev dependencies and New Relic. It still built.

Then I added back New Relic and the build failed.

That’s as far as I got. If you can narrow down what combination of dependencies causes the problem then maybe we can figure out why they’re conflicting and which project might need to be updated.

1 Like

By the way, I got rid of the @expo/config-plugins@4.1.5 warning by upgrading jest-expo

$ npm why @expo/config-plugins@4.1.5
@expo/config-plugins@4.1.5 dev
node_modules/jest-expo/node_modules/@expo/config-plugins
  @expo/config-plugins@"4.1.5" from @expo/config@6.0.26
  node_modules/jest-expo/node_modules/@expo/config
    @expo/config@"^6.0.6" from jest-expo@44.0.1
    node_modules/jest-expo
      dev jest-expo@"^44.0.1" from the root project
$ yarn add 'jest-expo@^46.0.0'
1 Like

Thanks again! I will look into some of this some more and report back.

One other question for you, since I am not familiar with maintaining both Android & iOS, is it common that a package will work on one device build, but fail on the other? Basically like this situation?

I’m not the best person to answer that question :slight_smile:

Most of the native code is different on Android vs. iOS, so it’s quite possible that there would be a problem that only affects one platform. At least these days the default JavaScript engine on both platforms is Hermes, so that hopefully removes some of the differences.

How do I know what Android-SDK version I am on?

Maybe react-native-reanimated has an issue due to these other packages relying on the same thing, but different versions?

The frustrating part is when I run npx expo install it installs the version on my package.json above

If you run npx expo prebuild -p android in an Expo SDK 46 project, you’ll find the following in android/build.gradle:

        buildToolsVersion = findProperty('android.buildToolsVersion') ?: '31.0.0'
        minSdkVersion = Integer.parseInt(findProperty('android.minSdkVersion') ?: '21')
        compileSdkVersion = Integer.parseInt(findProperty('android.compileSdkVersion') ?: '31')
        targetSdkVersion = Integer.parseInt(findProperty('android.targetSdkVersion') ?: '31')

So I believe that unless you override these using BuildProperties, the minSdkVersion is 21 and the targetSdkVersion is 31. I don’t think that’s related to your build problems, though.

Actually, all of the ones in your screenshot are compatible with 2.9.x where x >= 1.

“^2.8.0” means it can be 2.x.y where x >= 8.
“~2.9.1” means it can be 2.9.x where x >= 1.

If you combine those constraints then they are both satisfied by 2.9.1 (or 2.9.2, etc.)

The other constraints in the screenshot are also all compatible with 2.9.1, so that version should be fine… based on the stated requirements.

But it does seem that there are two versions of the native code from react-native-reanimated for some reason and I’m not sure why that is. Based on the fact that adding the New Relic dependency seems to cause the breakage it seems like one of the versions must come along with that. But I don’t see why New Relic would include any react-native-reanimated code.

I might have gotten it to work on EAS! I added:

 "resolutions": {
   ...
    "react-native-gesture-handler": "~2.5.0"
  }

One thing tho, is that if I run all the prebuild locally, the prebuild run:android fails. Is this concerning? I was surprised because the EAS prebuild also runs

hmmm… I see you’ve added a screenshot with the react-native-gesture-handler versions. That looks more problematic.

If I install @gorhom/bottom-sheet, react-native-reanimated and react-native-gesture-handler in a new Expo SDK 46 app I get version 4.4.6 and:

% npm why react-native-gesture-handler
react-native-gesture-handler@2.5.0
node_modules/react-native-gesture-handler
  react-native-gesture-handler@"~2.5.0" from the root project
  peer react-native-gesture-handler@">=1.10.1" from @gorhom/bottom-sheet@4.4.6
  node_modules/@gorhom/bottom-sheet
    @gorhom/bottom-sheet@"^4.4.6" from the root project

But in your screenshot it looks like you have @gorhom/bottom-sheet 4.4.5 and it seems to want react-native-gesture-handler 1.x.y where x >= 10.

What did you run to generate the output in your screenshots?

EDIT:

If I manually install version 4.4.5 then I get basically the same npm why output:

% npm why react-native-gesture-handler
react-native-gesture-handler@2.5.0
node_modules/react-native-gesture-handler
  react-native-gesture-handler@"~2.5.0" from the root project
  peer react-native-gesture-handler@">=1.10.1" from @gorhom/bottom-sheet@4.4.5
  node_modules/@gorhom/bottom-sheet
    @gorhom/bottom-sheet@"4.4.5" from the root project

So I’m not sure why your screenshot seems to want “^1.10.3” (and “^1.6.1” for react-native-reanimated).

I just did a search on those libraries inside my node_modules folder, to be able to see package dependencies

Try running npm why react-native-gesture-handler and npm why react-native-reanimated

So this is really strange.

If I use the CI pipeline to build on EAS to install a “preview” app on physical device such as for QA team, with eas build --platform android --non-interactive --profile development-internal, it succeeds

However, if I try a build on EAS to install on the simulator with eas build --profile development --platform all, the build fails.

FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':app:mergeProjectDexDebug'.
A failure occurred while executing com.android.build.gradle.internal.tasks.DexMergingTaskDelegate
> There was a failure while executing work items
> A failure occurred while executing com.android.build.gradle.internal.tasks.DexMergingWorkAction
> com.android.builder.dexing.DexArchiveMergerException: Error while merging dex archives: 
Learn how to resolve the issue at https://developer.android.com/studio/build/dependencies#duplicate_classes.
           Type devmenu.com.swmansion.common.GestureHandlerStateManager is defined multiple times: /home/expo/workingdir/build/android/app/build/intermediates/mixed_scope_dex_archive/debug/out/1a170d0bd894adab65ecda3a076806fe255d0d45d8e915c332a70cd50745a1ea_0.jar:classes.dex, /home/expo/workingdir/build/android/app/build/intermediates/mixed_scope_dex_archive/debug/out/bdd639976e0a4ae11b223df553bc82888ce2938519c96fe038bfb09545b38fb7_0.jar:classes.dex

What could cause one to succeed & one to fail like this?

react-native-gesture-handler@2.5.0
node_modules/react-native-gesture-handler
  react-native-gesture-handler@"~2.5.0" from the root project
  peer react-native-gesture-handler@">=1.10.1" from @gorhom/bottom-sheet@4.4.6
  node_modules/@gorhom/bottom-sheet
    @gorhom/bottom-sheet@"^4.4.6" from the root project
  peer react-native-gesture-handler@">= 1.0.0" from @react-navigation/stack@6.3.16
  node_modules/@react-navigation/stack
    @react-navigation/stack@"^6.3.16" from the root project
  peer react-native-gesture-handler@">= 1.0.0" from @react-navigation/drawer@6.5.7
  node_modules/@react-navigation/drawer
    @react-navigation/drawer@"^6.5.7" from the root project

and

react-native-reanimated@2.9.1
node_modules/react-native-reanimated
  react-native-reanimated@"~2.9.1" from the root project
  peer react-native-reanimated@">=2.2.0" from @gorhom/bottom-sheet@4.4.6
  node_modules/@gorhom/bottom-sheet
    @gorhom/bottom-sheet@"^4.4.6" from the root project
  peer react-native-reanimated@">= 1.0.0" from @react-navigation/drawer@6.5.7
  node_modules/@react-navigation/drawer
    @react-navigation/drawer@"^6.5.7" from the root project

The dev menu (part of the dev client) has something to do with this. You don’t have developmentClient set to true in the development-internal profile, so that’s why that works.

Other than that I’m a bit lost as to what is going on.

Maybe try asking on the Expo Discord. If you are able to get help there I’d be interested in the cause and the solution.

ok. let’s see what happens there