Skip to content

UnusedModuleInterfaceParserError in NativeClerkModule during Android build (Expo SDK 55 / New Architecture) #8150

@anis-rangrez

Description

@anis-rangrez

Preliminary Checks

Reproduction

https://github.com/anis-rangrez

Publishable key

EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_Z2l2aW5nLXBpZ2Vvbi0zMS5jbGVyay5hY2NvdW50cy5kZXYk

Description

Title:

[Bug]: UnusedModuleInterfaceParserError in NativeClerkModule during Android build (Expo SDK 55 / New Architecture)

Environment:

  • OS: Windows
  • Package Manager: Bun
  • Node Version: 25.2.1
  • Expo SDK: 55.0.0
  • @clerk/clerk-expo Version: (Latest)

Description:

When trying to build the Android development client using the New Architecture / Codegen, the build completely fails at the :clerk_expo:generateCodegenSchemaFromJavaScript task.

React Native's Codegen is throwing an UnusedModuleInterfaceParserError because it finds an unused Spec interface inside NativeClerkModule.ts. It looks like the module is missing the TurboModuleRegistry.getEnforcing<Spec>('NativeClerkModule') export at the bottom of the file.

Note: I see there is a recent PR (#8112) that seems to address this, but the issue is currently blocking Android builds in production/development on the latest published version.

Steps to Reproduce:

  1. Initialize an Expo SDK 55 project with @clerk/clerk-expo.
  2. Run the Android build with Bun: bunx expo run:android
  3. The build fails during the Configure project :expo-modules-core phase.

Error Logs:

PS D:\Viblink> bunx expo run:android 
env: load .env.local
env: export EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY
✅ Clerk iOS plugin loaded
✅ Clerk Android plugin loaded
› Building app...
Configuration on demand is an incubating feature.

> Configure project :
[ExpoRootProject] Using the following versions:
  - buildTools:  36.0.0
  - minSdk:      24
  - compileSdk:  36
  - targetSdk:   36
  - ndk:         27.1.12297006
  - kotlin:      2.1.20
  - ksp:         2.1.20-2.0.1

> Configure project :app
 ??  Applying gradle plugin 'expo-max-sdk-override-plugin'
  [expo-max-sdk-override-plugin] This plugin will find all permissions declared with `android:maxSdkVersion`. If there exists a declaration with the `android:maxSdkVersion` annotation and another one without, the plugin will remove the annotation from the final merged manifest. In order to see a log with the changes run a clean build of the app.
 ??  Applying gradle plugin 'expo-dev-launcher-gradle-plugin'

> Configure project :expo

Using expo modules
  - expo-log-box (55.0.7)
  - expo-constants (55.0.9)
  - expo-dev-client (55.0.18)
  - expo-dev-launcher (55.0.19) [38s]
  - expo-dev-menu (55.0.16)
  - expo-dev-menu-interface (55.0.1)]
  - expo-json-utils (55.0.0)ING [39s]                                                          
  - expo-manifests (55.0.11)ING [40s]                                                          

> Configure project :expo-modules-core                                                         
Linking react-native-worklets native libs into expo-modules-core build tasks                   
task ':react-native-worklets:mergeDebugNativeLibs'
task ':react-native-worklets:mergeReleaseNativeLibs'

> Configure project :expo
  - expo-modules-core (55.0.17)
  - expo-updates-interface (55.1.3)s]
  - [?] expo-dom-webview (55.0.3)
  - [?] expo-application (55.0.10)2s]
  - [?] expo-asset (55.0.10)                                                                   
  - [?] expo-crypto (55.0.10)
  - [?] expo-file-system (55.0.11)
  - [?] expo-font (55.0.4)
  - [?] expo-image (55.0.6)
  - [?] expo-keep-awake (55.0.4)
  - [?] expo-linking (55.0.8)
  - [?] expo-router (55.0.7)
  - [?] expo-secure-store (55.0.9)
  - [?] expo-system-ui (55.0.10)
  - [?] expo-web-browser (55.0.10)


> Task :expo-constants:createExpoConfig
✅ Clerk iOS plugin loaded
✅ Clerk Android plugin loaded

> Task :clerk_expo:generateCodegenSchemaFromJavaScript FAILED                                  
D:\Viblink\node_modules\@react-native\codegen\lib\parsers\parsers-commons.js:511
        throw parsingErrors[0];
        ^

UnusedModuleInterfaceParserError: Module NativeClerkModule: Unused NativeModule spec. Please load the NativeModule by calling TurboModuleRegistry.get<Spec>('<moduleName>').
    at throwIfUnusedModuleInterfaceParserError (D:\Viblink\node_modules\@react-native\codegen\lib\parsers\error-utils.js:77:11)
    at parseModuleName (D:\Viblink\node_modules\@react-native\codegen\lib\parsers\parsers-commons.js:579:3)
    at buildModuleSchema (D:\Viblink\node_modules\@react-native\codegen\lib\parsers\parsers-commons.js:647:22)
    at D:\Viblink\node_modules\@react-native\codegen\lib\parsers\parsers-commons.js:494:9      
    at guard (D:\Viblink\node_modules\@react-native\codegen\lib\parsers\utils.js:30:14)        
    at buildSchemaFromConfigType (D:\Viblink\node_modules\@react-native\codegen\lib\parsers\parsers-commons.js:493:22)
    at buildSchema (D:\Viblink\node_modules\@react-native\codegen\lib\parsers\parsers-commons.js:546:10)
    at TypeScriptParser.parseString (D:\Viblink\node_modules\@react-native\codegen\lib\parsers\typescript\parser.js:146:12)
    at TypeScriptParser.parseFile (D:\Viblink\node_modules\@react-native\codegen\lib\parsers\typescript\parser.js:143:17)
    at files.reduce.modules (D:\Viblink\node_modules\@react-native\codegen\lib\cli\combine\combine-js-to-schema.js:33:31) {
  nodes: [
    Node {
      type: 'TSInterfaceDeclaration',
      start: 197,
      end: 569,
      loc: SourceLocation {
        start: Position { line: 5, column: 7, index: 197 },
        end: Position { line: 12, column: 1, index: 569 },
        filename: undefined,
        identifierName: undefined
      },
      id: Node {
        type: 'Identifier',
        start: 207,
        end: 211,
        loc: SourceLocation {
          start: Position { line: 5, column: 17, index: 207 },
          end: Position { line: 5, column: 21, index: 211 },
          filename: undefined,
          identifierName: 'Spec'
        },
        name: 'Spec'
      },
      typeParameters: undefined,
      extends: [
        Node {
          type: 'TSExpressionWithTypeArguments',
          start: 220,
          end: 231,
          loc: SourceLocation {
            start: [Position],
            end: [Position],
            filename: undefined,
            identifierName: undefined
          },
          expression: Node {
            type: 'Identifier',
            start: 220,
            end: 231,
            loc: [SourceLocation],
            name: 'TurboModule'
          }
        }
      ],
      body: Node {
        type: 'TSInterfaceBody',
        start: 232,
        end: 569,
        loc: SourceLocation {
          start: Position { line: 5, column: 42, index: 232 },
          end: Position { line: 12, column: 1, index: 569 },
          filename: undefined,
          identifierName: undefined
        },
        body: [
          Node {
            type: 'TSMethodSignature',
            start: 236,
            end: 313,
            loc: [SourceLocation],
            key: [Node],
            computed: false,
            typeParameters: undefined,
            parameters: [Array],
            typeAnnotation: [Node],
            kind: 'method'
          },
          Node {
            type: 'TSMethodSignature',
            start: 316,
            end: 374,
            loc: [SourceLocation],
            key: [Node],
            computed: false,
            typeParameters: undefined,
            parameters: [Array],
            typeAnnotation: [Node],
            kind: 'method'
          },
          Node {
            type: 'TSMethodSignature',
            start: 377,
            end: 449,
            loc: [SourceLocation],
            key: [Node],
            computed: false,
            typeParameters: undefined,
            parameters: [Array],
            typeAnnotation: [Node],
            kind: 'method'
          },
          Node {
            type: 'TSMethodSignature',
            start: 452,
            end: 495,
            loc: [SourceLocation],
            key: [Node],
            computed: false,
            typeParameters: undefined,
            parameters: [],
            typeAnnotation: [Node],
            kind: 'method'
          },
          Node {
            type: 'TSMethodSignature',
            start: 498,
            end: 539,
            loc: [SourceLocation],
            key: [Node],
            computed: false,
            typeParameters: undefined,
            parameters: [],
            typeAnnotation: [Node],
            kind: 'method'
          },
          Node {
            type: 'TSMethodSignature',
            start: 542,
            end: 567,
            loc: [SourceLocation],
            key: [Node],
            computed: false,
            typeParameters: undefined,
            parameters: [],
            typeAnnotation: [Node],
            kind: 'method'
          }
        ]
      }
    }
  ]
}

Node.js v25.2.1

[Incubating] Problems report is available at: file:///D:/Viblink/android/build/reports/problems/problems-report.html

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':clerk_expo:generateCodegenSchemaFromJavaScript'.
> Process 'command 'cmd'' finished with non-zero exit value 1

* 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 generate a Build Scan (Powered by Develocity).
> Get more help at https://help.gradle.org.

Deprecated Gradle features were used in this build, making it incompatible with Gradle 10.     

You can use '--warning-mode all' to show the individual deprecation warnings and determine if they come from your own scripts or plugins.

For more on this, please refer to https://docs.gradle.org/9.0.0/userguide/command_line_interface.html#sec:command_line_warnings in the Gradle documentation.

BUILD FAILED in 1m 5s
49 actionable tasks: 17 executed, 32 up-to-date
Error: D:\Viblink\android\gradlew.bat app:assembleDebug -x lint -x test --configure-on-demand --build-cache -PreactNativeDevServerPort=8081 -PreactNativeArchitectures=x86_64,arm64-v8a exited with non-zero code: 1
Error: D:\Viblink\android\gradlew.bat app:assembleDebug -x lint -x test --configure-on-demand --build-cache -PreactNativeDevServerPort=8081 -PreactNativeArchitectures=x86_64,arm64-v8a exited with non-zero code: 1
    at ChildProcess.completionListener (D:\Viblink\node_modules\@expo\spawn-async\src\spawnAsync.ts:67:13)
    at Object.onceWrapper (node:events:623:26)
    at ChildProcess.emit (node:events:508:28)
    at ChildProcess.cp.emit (D:\Viblink\node_modules\cross-spawn\lib\enoent.js:34:29)
    at maybeClose (node:internal/child_process:1085:16)
    at Process.ChildProcess._handle.onexit (node:internal/child_process:304:5)
    ...
    at spawnAsync (D:\Viblink\node_modules\@expo\spawn-async\src\spawnAsync.ts:28:21)
    at spawnGradleAsync (D:\Viblink\node_modules\@expo\cli\src\start\platforms\android\gradle.ts:134:28)
    at assembleAsync (D:\Viblink\node_modules\@expo\cli\src\start\platforms\android\gradle.ts:83:16)
    at runAndroidAsync (D:\Viblink\node_modules\@expo\cli\src\run\android\runAndroidAsync.ts:62:24)

### Environment

```Shell
### Environment:
- **OS:** Windows
- **Package Manager:** Bun
- **Node Version:** 25.2.1
- **Expo SDK:** 55.0.0
- **@clerk/clerk-expo Version:** (Latest)

Metadata

Metadata

Assignees

No one assigned

    Labels

    needs-triageA ticket that needs to be triaged by a team member

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions