From ae6b38b925a2628cd51a042a91a4c57b10d7691a Mon Sep 17 00:00:00 2001 From: AbbanMustafa Date: Mon, 4 May 2026 18:10:15 -0400 Subject: [PATCH 1/3] [build-tools] - Add additional known error categories to build error handlers --- .../buildErrors/__tests__/detectError.test.ts | 280 +++++++++++++++++- .../src/buildErrors/buildErrorHandlers.ts | 101 +++++++ 2 files changed, 379 insertions(+), 2 deletions(-) diff --git a/packages/build-tools/src/buildErrors/__tests__/detectError.test.ts b/packages/build-tools/src/buildErrors/__tests__/detectError.test.ts index 50ee3672fc..d3228ef2d3 100644 --- a/packages/build-tools/src/buildErrors/__tests__/detectError.test.ts +++ b/packages/build-tools/src/buildErrors/__tests__/detectError.test.ts @@ -76,7 +76,9 @@ describe(resolveBuildPhaseErrorAsync, () => { expect(err.message).toBe( 'Unknown error. See logs of the Install dependencies build phase for more information.' ); - expect(err.trackingCode).toBeUndefined(); + // The specific bundler handler doesn't match (wrong phase), but the + // INSTALL_DEPENDENCIES_GENERIC_FAILURE catch-all now picks it up + expect(err.trackingCode).toBe('INSTALL_DEPENDENCIES_GENERIC_FAILURE'); }); it('detects npm cache error if cache is enabled', async () => { @@ -122,7 +124,9 @@ describe(resolveBuildPhaseErrorAsync, () => { expect(err.message).toBe( 'Unknown error. See logs of the Install dependencies build phase for more information.' ); - expect(err.trackingCode).toBeUndefined(); + // The npm cache handler doesn't match (cache disabled), but the + // INSTALL_DEPENDENCIES_GENERIC_FAILURE catch-all now picks it up + expect(err.trackingCode).toBe('INSTALL_DEPENDENCIES_GENERIC_FAILURE'); }); it('detects xcode line error', async () => { @@ -309,4 +313,276 @@ Refer to "Xcode Logs" below for additional, more detailed logs.`); `Gradle build failed with unknown error. See logs for the "Run gradlew" phase for more information.` ); }); + + // --- Tests for new build error handlers (tracking codes) --- + + it('detects NPM_ERESOLVE tracking code', async () => { + const err = await resolveBuildPhaseErrorAsync( + new Error(), + [ + 'npm ERR! code ERESOLVE', + 'npm ERR! ERESOLVE could not resolve', + 'npm ERR! While resolving: react-native@0.71.0', + ], + { + job: { platform: Platform.ANDROID } as Job, + phase: BuildPhase.INSTALL_DEPENDENCIES, + env: {}, + }, + '/fake/path' + ); + expect(err.errorCode).toBe(errors.ErrorCode.UNKNOWN_ERROR); + expect(err.trackingCode).toBe('NPM_ERESOLVE'); + }); + + it('detects NPM_ERROR tracking code for generic npm errors', async () => { + const err = await resolveBuildPhaseErrorAsync( + new Error(), + ['npm ERR! 404 Not Found - GET https://registry.npmjs.org/nonexistent-package'], + { + job: { platform: Platform.ANDROID } as Job, + phase: BuildPhase.INSTALL_DEPENDENCIES, + env: {}, + }, + '/fake/path' + ); + expect(err.errorCode).toBe(errors.ErrorCode.UNKNOWN_ERROR); + expect(err.trackingCode).toBe('NPM_ERROR'); + }); + + it('detects METRO_UNABLE_TO_RESOLVE tracking code', async () => { + const err = await resolveBuildPhaseErrorAsync( + new Error(), + [ + 'error: Unable to resolve module ./src/missing from /home/expo/workingdir/build/index.js: ', + 'None of these files exist:', + ], + { + job: { platform: Platform.ANDROID } as Job, + phase: BuildPhase.PREBUILD, + env: {}, + }, + '/fake/path' + ); + expect(err.errorCode).toBe(errors.ErrorCode.UNKNOWN_ERROR); + expect(err.trackingCode).toBe('METRO_UNABLE_TO_RESOLVE'); + }); + + it('detects METRO_UNABLE_TO_RESOLVE without phase restriction', async () => { + const err = await resolveBuildPhaseErrorAsync( + new Error(), + ['error: Unable to resolve module @react-native/assets from /home/expo/workingdir/build/App.js'], + { + job: { platform: Platform.ANDROID } as Job, + phase: BuildPhase.EAGER_BUNDLE, + env: {}, + }, + '/fake/path' + ); + expect(err.errorCode).toBe(errors.ErrorCode.UNKNOWN_ERROR); + expect(err.trackingCode).toBe('METRO_UNABLE_TO_RESOLVE'); + }); + + it('detects PNPM_ERROR tracking code', async () => { + const err = await resolveBuildPhaseErrorAsync( + new Error(), + [ + ' ERR_PNPM_PEER_DEP_ISSUES Unmet peer dependencies', + 'hint: If you want peer dependencies to be automatically installed, add "auto-install-peers=true" to an .npmrc file.', + ], + { + job: { platform: Platform.ANDROID } as Job, + phase: BuildPhase.INSTALL_DEPENDENCIES, + env: {}, + }, + '/fake/path' + ); + expect(err.errorCode).toBe(errors.ErrorCode.UNKNOWN_ERROR); + expect(err.trackingCode).toBe('PNPM_ERROR'); + }); + + it('does not detect PNPM_ERROR outside INSTALL_DEPENDENCIES phase', async () => { + const err = await resolveBuildPhaseErrorAsync( + new Error(), + [' ERR_PNPM_PEER_DEP_ISSUES Unmet peer dependencies'], + { + job: { platform: Platform.ANDROID } as Job, + phase: BuildPhase.PREBUILD, + env: {}, + }, + '/fake/path' + ); + expect(err.errorCode).toBe(errors.ErrorCode.UNKNOWN_ERROR); + expect(err.trackingCode).toBeUndefined(); + }); + + it('detects PREBUILD_DANGEROUS_MOD_ENOENT tracking code', async () => { + const err = await resolveBuildPhaseErrorAsync( + new Error(), + [ + "Error: [android.dangerous]: withAndroidDangerousBaseMod: ENOENT: no such file or directory, open './assets/splash.png'", + ], + { + job: { platform: Platform.ANDROID } as Job, + phase: BuildPhase.PREBUILD, + env: {}, + }, + '/fake/path' + ); + expect(err.errorCode).toBe(errors.ErrorCode.UNKNOWN_ERROR); + expect(err.trackingCode).toBe('PREBUILD_DANGEROUS_MOD_ENOENT'); + }); + + it('detects PREBUILD_DANGEROUS_MOD_ENOENT for iOS', async () => { + const err = await resolveBuildPhaseErrorAsync( + new Error(), + [ + "Error: [ios.dangerous]: withIosDangerousBaseMod: ENOENT: no such file or directory, open './assets/fonts/CustomFont.ttf'", + ], + { + job: { platform: Platform.IOS } as Job, + phase: BuildPhase.PREBUILD, + env: {}, + }, + '/fake/path' + ); + expect(err.errorCode).toBe(errors.ErrorCode.UNKNOWN_ERROR); + expect(err.trackingCode).toBe('PREBUILD_DANGEROUS_MOD_ENOENT'); + }); + + it('detects SYNTAX_ERROR tracking code', async () => { + const err = await resolveBuildPhaseErrorAsync( + new Error(), + ['SyntaxError: Unexpected token } in JSON at position 1234'], + { + job: { platform: Platform.ANDROID } as Job, + phase: BuildPhase.PREBUILD, + env: {}, + }, + '/fake/path' + ); + expect(err.errorCode).toBe(errors.ErrorCode.UNKNOWN_ERROR); + expect(err.trackingCode).toBe('SYNTAX_ERROR'); + }); + + it('detects COCOAPODS_GENERIC_ERROR tracking code', async () => { + const err = await resolveBuildPhaseErrorAsync( + new Error(), + ['[!] Unable to find a specification for `SomeUnknownPod`'], + { + job: { platform: Platform.IOS } as Job, + phase: BuildPhase.INSTALL_PODS, + env: {}, + }, + '/fake/path' + ); + expect(err.errorCode).toBe(errors.ErrorCode.UNKNOWN_ERROR); + expect(err.trackingCode).toBe('COCOAPODS_GENERIC_ERROR'); + }); + + it('does not detect COCOAPODS_GENERIC_ERROR for Android', async () => { + const err = await resolveBuildPhaseErrorAsync( + new Error(), + ['[!] Some error'], + { + job: { platform: Platform.ANDROID } as Job, + phase: BuildPhase.INSTALL_PODS, + env: {}, + }, + '/fake/path' + ); + expect(err.errorCode).toBe(errors.ErrorCode.UNKNOWN_ERROR); + expect(err.trackingCode).toBeUndefined(); + }); + + it('detects INSTALL_DEPENDENCIES_GENERIC_FAILURE as catch-all', async () => { + const err = await resolveBuildPhaseErrorAsync( + new Error(), + ['some random error that does not match any specific pattern'], + { + job: { platform: Platform.ANDROID } as Job, + phase: BuildPhase.INSTALL_DEPENDENCIES, + env: {}, + }, + '/fake/path' + ); + expect(err.errorCode).toBe(errors.ErrorCode.UNKNOWN_ERROR); + expect(err.trackingCode).toBe('INSTALL_DEPENDENCIES_GENERIC_FAILURE'); + }); + + it('detects MONOREPO_PACKAGE_JSON_NOT_FOUND tracking code', async () => { + const err = await resolveBuildPhaseErrorAsync( + new Error(), + ['Error: package.json does not exist at /home/expo/workingdir/build/packages/app'], + { + job: { platform: Platform.ANDROID } as Job, + phase: BuildPhase.INSTALL_DEPENDENCIES, + env: {}, + }, + '/fake/path' + ); + // MONOREPO_PACKAGE_JSON_NOT_FOUND should match before INSTALL_DEPENDENCIES_GENERIC_FAILURE + expect(err.errorCode).toBe(errors.ErrorCode.UNKNOWN_ERROR); + expect(err.trackingCode).toBe('MONOREPO_PACKAGE_JSON_NOT_FOUND'); + }); + + it('detects EXPO_CONFIG_ERROR tracking code', async () => { + const err = await resolveBuildPhaseErrorAsync( + new Error(), + ['ConfigError: Property "expo.ios.bundleIdentifier" in app.json is invalid.'], + { + job: { platform: Platform.IOS } as Job, + phase: BuildPhase.PREBUILD, + env: {}, + }, + '/fake/path' + ); + expect(err.errorCode).toBe(errors.ErrorCode.UNKNOWN_ERROR); + expect(err.trackingCode).toBe('EXPO_CONFIG_ERROR'); + }); + + it('detects RUNTIME_VERSION_MISMATCH tracking code', async () => { + const err = await resolveBuildPhaseErrorAsync( + new Error(), + ['Error: runtimeVersion in Expo.plist policies must be set to a valid value.'], + { + job: { platform: Platform.IOS } as Job, + phase: BuildPhase.CONFIGURE_EXPO_UPDATES, + env: {}, + }, + '/fake/path' + ); + expect(err.errorCode).toBe(errors.ErrorCode.UNKNOWN_ERROR); + expect(err.trackingCode).toBe('RUNTIME_VERSION_MISMATCH'); + }); + + it('does not detect RUNTIME_VERSION_MISMATCH outside CONFIGURE_EXPO_UPDATES phase', async () => { + const err = await resolveBuildPhaseErrorAsync( + new Error(), + ['Error: runtimeVersion in Expo.plist policies must be set to a valid value.'], + { + job: { platform: Platform.IOS } as Job, + phase: BuildPhase.PREBUILD, + env: {}, + }, + '/fake/path' + ); + expect(err.errorCode).toBe(errors.ErrorCode.UNKNOWN_ERROR); + expect(err.trackingCode).toBeUndefined(); + }); + + it('detects CONFIG_PLUGIN_RESOLVE_ERROR tracking code', async () => { + const err = await resolveBuildPhaseErrorAsync( + new Error(), + ['Error: Failed to resolve plugin for module "expo-camera" relative to "/home/expo/workingdir/build"'], + { + job: { platform: Platform.ANDROID } as Job, + phase: BuildPhase.PREBUILD, + env: {}, + }, + '/fake/path' + ); + expect(err.errorCode).toBe(errors.ErrorCode.UNKNOWN_ERROR); + expect(err.trackingCode).toBe('CONFIG_PLUGIN_RESOLVE_ERROR'); + }); }); diff --git a/packages/build-tools/src/buildErrors/buildErrorHandlers.ts b/packages/build-tools/src/buildErrors/buildErrorHandlers.ts index 854defad6f..5522a7c087 100644 --- a/packages/build-tools/src/buildErrors/buildErrorHandlers.ts +++ b/packages/build-tools/src/buildErrors/buildErrorHandlers.ts @@ -361,4 +361,105 @@ export const buildErrorHandlers: ErrorHandler[] = [ 'fastlane: Bundle React Native code and images failed.' ), }, + // --- Specific patterns for reducing unknown_error bucket --- + { + phase: BuildPhase.INSTALL_DEPENDENCIES, + // npm ERR! ERESOLVE could not resolve + regexp: /npm ERR!.*ERESOLVE|ERESOLVE could not resolve/, + createError: () => new TrackedBuildError('NPM_ERESOLVE', 'npm: ERESOLVE could not resolve.'), + }, + { + phase: BuildPhase.INSTALL_DEPENDENCIES, + // ERR_PNPM_PEER_DEP_ISSUES or other pnpm errors + regexp: /ERR_PNPM_/, + createError: () => new TrackedBuildError('PNPM_ERROR', 'pnpm: error during install.'), + }, + { + // Can occur in PREBUILD, EAGER_BUNDLE, or other phases + // Unable to resolve module `./src/missing` from `index.js` + regexp: /Unable to resolve module/, + createError: () => + new TrackedBuildError('METRO_UNABLE_TO_RESOLVE', 'metro: Unable to resolve module.'), + }, + { + phase: BuildPhase.PREBUILD, + // Error: [android.dangerous]: withAndroidDangerousBaseMod: ENOENT: no such file or directory, open './assets/splash.png' + // Must come AFTER EXPO_CLI_MISSING_ICON which matches the icon-specific subset + regexp: /with(?:Android|Ios)DangerousBaseMod:.*ENOENT/, + createError: () => + new TrackedBuildError( + 'PREBUILD_DANGEROUS_MOD_ENOENT', + 'prebuild: ENOENT in dangerous base mod.' + ), + }, + { + // SyntaxError: Unexpected token ... + regexp: /SyntaxError:/, + createError: () => new TrackedBuildError('SYNTAX_ERROR', 'SyntaxError encountered.'), + }, + { + // package.json does not exist (common in monorepos with wrong working directory) + regexp: /package\.json does not exist/, + createError: () => + new TrackedBuildError( + 'MONOREPO_PACKAGE_JSON_NOT_FOUND', + 'package.json does not exist.' + ), + }, + { + // ConfigError: Property ... in app.json is invalid + regexp: /ConfigError:/, + createError: () => + new TrackedBuildError('EXPO_CONFIG_ERROR', 'expo: ConfigError encountered.'), + }, + { + phase: BuildPhase.CONFIGURE_EXPO_UPDATES, + // runtimeVersion policies must be set ... + // runtime version is not equal ... + regexp: /runtimeVersion.*policies.*must.*set|runtime version.*not.*equal/i, + createError: () => + new TrackedBuildError( + 'RUNTIME_VERSION_MISMATCH', + 'expo-updates: runtime version mismatch.' + ), + }, + { + phase: BuildPhase.PREBUILD, + // Failed to resolve plugin for module "expo-camera" ... + regexp: /Failed to resolve plugin/, + createError: () => + new TrackedBuildError( + 'CONFIG_PLUGIN_RESOLVE_ERROR', + 'prebuild: Failed to resolve config plugin.' + ), + }, + // --- Broader catch-all patterns (must come after specific patterns) --- + { + phase: BuildPhase.INSTALL_DEPENDENCIES, + // Catch-all for npm errors not matched by specific handlers above + // npm ERR! 404 Not Found - GET https://registry.npmjs.org/... + regexp: /npm ERR!/, + createError: () => new TrackedBuildError('NPM_ERROR', 'npm: generic error.'), + }, + { + platform: Platform.IOS, + phase: BuildPhase.INSTALL_PODS, + // [!] CocoaPods error indicator - catch-all for pod errors not matched above + regexp: /\[!\]/, + createError: () => + new TrackedBuildError( + 'COCOAPODS_GENERIC_ERROR', + 'cocoapods: generic error.' + ), + }, + { + phase: BuildPhase.INSTALL_DEPENDENCIES, + // Catch-all for any install_dependencies failure - must be LAST handler with this phase + regexp: /.*/, + createError: () => + new TrackedBuildError( + 'INSTALL_DEPENDENCIES_GENERIC_FAILURE', + 'install_dependencies: generic failure.' + ), + }, ]; From 245942348d9208abb5c9927fa86db9c47d2fa5df Mon Sep 17 00:00:00 2001 From: AbbanMustafa Date: Mon, 4 May 2026 21:46:07 -0400 Subject: [PATCH 2/3] fmt --- .../buildErrors/__tests__/detectError.test.ts | 8 ++++++-- .../src/buildErrors/buildErrorHandlers.ts | 18 ++++-------------- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/packages/build-tools/src/buildErrors/__tests__/detectError.test.ts b/packages/build-tools/src/buildErrors/__tests__/detectError.test.ts index d3228ef2d3..457bcfd5aa 100644 --- a/packages/build-tools/src/buildErrors/__tests__/detectError.test.ts +++ b/packages/build-tools/src/buildErrors/__tests__/detectError.test.ts @@ -371,7 +371,9 @@ Refer to "Xcode Logs" below for additional, more detailed logs.`); it('detects METRO_UNABLE_TO_RESOLVE without phase restriction', async () => { const err = await resolveBuildPhaseErrorAsync( new Error(), - ['error: Unable to resolve module @react-native/assets from /home/expo/workingdir/build/App.js'], + [ + 'error: Unable to resolve module @react-native/assets from /home/expo/workingdir/build/App.js', + ], { job: { platform: Platform.ANDROID } as Job, phase: BuildPhase.EAGER_BUNDLE, @@ -574,7 +576,9 @@ Refer to "Xcode Logs" below for additional, more detailed logs.`); it('detects CONFIG_PLUGIN_RESOLVE_ERROR tracking code', async () => { const err = await resolveBuildPhaseErrorAsync( new Error(), - ['Error: Failed to resolve plugin for module "expo-camera" relative to "/home/expo/workingdir/build"'], + [ + 'Error: Failed to resolve plugin for module "expo-camera" relative to "/home/expo/workingdir/build"', + ], { job: { platform: Platform.ANDROID } as Job, phase: BuildPhase.PREBUILD, diff --git a/packages/build-tools/src/buildErrors/buildErrorHandlers.ts b/packages/build-tools/src/buildErrors/buildErrorHandlers.ts index 5522a7c087..c497ba0562 100644 --- a/packages/build-tools/src/buildErrors/buildErrorHandlers.ts +++ b/packages/build-tools/src/buildErrors/buildErrorHandlers.ts @@ -401,16 +401,12 @@ export const buildErrorHandlers: ErrorHandler[] = [ // package.json does not exist (common in monorepos with wrong working directory) regexp: /package\.json does not exist/, createError: () => - new TrackedBuildError( - 'MONOREPO_PACKAGE_JSON_NOT_FOUND', - 'package.json does not exist.' - ), + new TrackedBuildError('MONOREPO_PACKAGE_JSON_NOT_FOUND', 'package.json does not exist.'), }, { // ConfigError: Property ... in app.json is invalid regexp: /ConfigError:/, - createError: () => - new TrackedBuildError('EXPO_CONFIG_ERROR', 'expo: ConfigError encountered.'), + createError: () => new TrackedBuildError('EXPO_CONFIG_ERROR', 'expo: ConfigError encountered.'), }, { phase: BuildPhase.CONFIGURE_EXPO_UPDATES, @@ -418,10 +414,7 @@ export const buildErrorHandlers: ErrorHandler[] = [ // runtime version is not equal ... regexp: /runtimeVersion.*policies.*must.*set|runtime version.*not.*equal/i, createError: () => - new TrackedBuildError( - 'RUNTIME_VERSION_MISMATCH', - 'expo-updates: runtime version mismatch.' - ), + new TrackedBuildError('RUNTIME_VERSION_MISMATCH', 'expo-updates: runtime version mismatch.'), }, { phase: BuildPhase.PREBUILD, @@ -447,10 +440,7 @@ export const buildErrorHandlers: ErrorHandler[] = [ // [!] CocoaPods error indicator - catch-all for pod errors not matched above regexp: /\[!\]/, createError: () => - new TrackedBuildError( - 'COCOAPODS_GENERIC_ERROR', - 'cocoapods: generic error.' - ), + new TrackedBuildError('COCOAPODS_GENERIC_ERROR', 'cocoapods: generic error.'), }, { phase: BuildPhase.INSTALL_DEPENDENCIES, From 0f1fe92a46804ba0acd2f8ee0ee9a0a9a061d6e0 Mon Sep 17 00:00:00 2001 From: AbbanMustafa Date: Tue, 5 May 2026 01:17:30 -0400 Subject: [PATCH 3/3] remove catchalls --- .../buildErrors/__tests__/detectError.test.ts | 69 +------------------ .../src/buildErrors/buildErrorHandlers.ts | 26 ------- 2 files changed, 2 insertions(+), 93 deletions(-) diff --git a/packages/build-tools/src/buildErrors/__tests__/detectError.test.ts b/packages/build-tools/src/buildErrors/__tests__/detectError.test.ts index 457bcfd5aa..f49e270318 100644 --- a/packages/build-tools/src/buildErrors/__tests__/detectError.test.ts +++ b/packages/build-tools/src/buildErrors/__tests__/detectError.test.ts @@ -76,9 +76,7 @@ describe(resolveBuildPhaseErrorAsync, () => { expect(err.message).toBe( 'Unknown error. See logs of the Install dependencies build phase for more information.' ); - // The specific bundler handler doesn't match (wrong phase), but the - // INSTALL_DEPENDENCIES_GENERIC_FAILURE catch-all now picks it up - expect(err.trackingCode).toBe('INSTALL_DEPENDENCIES_GENERIC_FAILURE'); + expect(err.trackingCode).toBeUndefined(); }); it('detects npm cache error if cache is enabled', async () => { @@ -124,9 +122,7 @@ describe(resolveBuildPhaseErrorAsync, () => { expect(err.message).toBe( 'Unknown error. See logs of the Install dependencies build phase for more information.' ); - // The npm cache handler doesn't match (cache disabled), but the - // INSTALL_DEPENDENCIES_GENERIC_FAILURE catch-all now picks it up - expect(err.trackingCode).toBe('INSTALL_DEPENDENCIES_GENERIC_FAILURE'); + expect(err.trackingCode).toBeUndefined(); }); it('detects xcode line error', async () => { @@ -335,21 +331,6 @@ Refer to "Xcode Logs" below for additional, more detailed logs.`); expect(err.trackingCode).toBe('NPM_ERESOLVE'); }); - it('detects NPM_ERROR tracking code for generic npm errors', async () => { - const err = await resolveBuildPhaseErrorAsync( - new Error(), - ['npm ERR! 404 Not Found - GET https://registry.npmjs.org/nonexistent-package'], - { - job: { platform: Platform.ANDROID } as Job, - phase: BuildPhase.INSTALL_DEPENDENCIES, - env: {}, - }, - '/fake/path' - ); - expect(err.errorCode).toBe(errors.ErrorCode.UNKNOWN_ERROR); - expect(err.trackingCode).toBe('NPM_ERROR'); - }); - it('detects METRO_UNABLE_TO_RESOLVE tracking code', async () => { const err = await resolveBuildPhaseErrorAsync( new Error(), @@ -467,51 +448,6 @@ Refer to "Xcode Logs" below for additional, more detailed logs.`); expect(err.trackingCode).toBe('SYNTAX_ERROR'); }); - it('detects COCOAPODS_GENERIC_ERROR tracking code', async () => { - const err = await resolveBuildPhaseErrorAsync( - new Error(), - ['[!] Unable to find a specification for `SomeUnknownPod`'], - { - job: { platform: Platform.IOS } as Job, - phase: BuildPhase.INSTALL_PODS, - env: {}, - }, - '/fake/path' - ); - expect(err.errorCode).toBe(errors.ErrorCode.UNKNOWN_ERROR); - expect(err.trackingCode).toBe('COCOAPODS_GENERIC_ERROR'); - }); - - it('does not detect COCOAPODS_GENERIC_ERROR for Android', async () => { - const err = await resolveBuildPhaseErrorAsync( - new Error(), - ['[!] Some error'], - { - job: { platform: Platform.ANDROID } as Job, - phase: BuildPhase.INSTALL_PODS, - env: {}, - }, - '/fake/path' - ); - expect(err.errorCode).toBe(errors.ErrorCode.UNKNOWN_ERROR); - expect(err.trackingCode).toBeUndefined(); - }); - - it('detects INSTALL_DEPENDENCIES_GENERIC_FAILURE as catch-all', async () => { - const err = await resolveBuildPhaseErrorAsync( - new Error(), - ['some random error that does not match any specific pattern'], - { - job: { platform: Platform.ANDROID } as Job, - phase: BuildPhase.INSTALL_DEPENDENCIES, - env: {}, - }, - '/fake/path' - ); - expect(err.errorCode).toBe(errors.ErrorCode.UNKNOWN_ERROR); - expect(err.trackingCode).toBe('INSTALL_DEPENDENCIES_GENERIC_FAILURE'); - }); - it('detects MONOREPO_PACKAGE_JSON_NOT_FOUND tracking code', async () => { const err = await resolveBuildPhaseErrorAsync( new Error(), @@ -523,7 +459,6 @@ Refer to "Xcode Logs" below for additional, more detailed logs.`); }, '/fake/path' ); - // MONOREPO_PACKAGE_JSON_NOT_FOUND should match before INSTALL_DEPENDENCIES_GENERIC_FAILURE expect(err.errorCode).toBe(errors.ErrorCode.UNKNOWN_ERROR); expect(err.trackingCode).toBe('MONOREPO_PACKAGE_JSON_NOT_FOUND'); }); diff --git a/packages/build-tools/src/buildErrors/buildErrorHandlers.ts b/packages/build-tools/src/buildErrors/buildErrorHandlers.ts index c497ba0562..fc3579c175 100644 --- a/packages/build-tools/src/buildErrors/buildErrorHandlers.ts +++ b/packages/build-tools/src/buildErrors/buildErrorHandlers.ts @@ -426,30 +426,4 @@ export const buildErrorHandlers: ErrorHandler[] = [ 'prebuild: Failed to resolve config plugin.' ), }, - // --- Broader catch-all patterns (must come after specific patterns) --- - { - phase: BuildPhase.INSTALL_DEPENDENCIES, - // Catch-all for npm errors not matched by specific handlers above - // npm ERR! 404 Not Found - GET https://registry.npmjs.org/... - regexp: /npm ERR!/, - createError: () => new TrackedBuildError('NPM_ERROR', 'npm: generic error.'), - }, - { - platform: Platform.IOS, - phase: BuildPhase.INSTALL_PODS, - // [!] CocoaPods error indicator - catch-all for pod errors not matched above - regexp: /\[!\]/, - createError: () => - new TrackedBuildError('COCOAPODS_GENERIC_ERROR', 'cocoapods: generic error.'), - }, - { - phase: BuildPhase.INSTALL_DEPENDENCIES, - // Catch-all for any install_dependencies failure - must be LAST handler with this phase - regexp: /.*/, - createError: () => - new TrackedBuildError( - 'INSTALL_DEPENDENCIES_GENERIC_FAILURE', - 'install_dependencies: generic failure.' - ), - }, ];