-
Notifications
You must be signed in to change notification settings - Fork 161
Open
Labels
needs reviewIssue is ready to be reviewed by a maintainerIssue is ready to be reviewed by a maintainer
Description
Build/Submit details page URL
https://expo.dev/accounts/alvie1/projects/hygo/workflows/019ac60c-89aa-7f4b-85c1-1c8888b18456
Summary
When using eas/repack in EAS Build workflows, the repack process fails on iOS but succeeds on Android. The error occurs during the expo export:embed step when Metro tries to load metro.config.js.
Error Message
Error: Found config at /Users/expo/workingdir/build/apps/mobile/metro.config.js that could not be
loaded with Node.js. at loadConfigFile (/Users/expo/workingdir/build/apps/mobile/node_modules/@expo/metro/node_modules/metro-config/src/loadConfig.js:263:15)
Environment
- EAS Build Profile: e2e-tests-repack
- Platform: iOS (fails) vs Android (works)
- Node version: 22.12.0 (configured in eas.json)
- Metro config: TypeScript file (metro.config.ts) loaded via JavaScript wrapper (metro.config.js)
Reproduction
metro.config.js
require("tsx/cjs");
module.exports = require("./metro.config.ts");
metro.config.ts
import { workspaceRoot } from "@nx/devkit";
import { getResolveRequest } from "@nx/expo/plugins/metro-resolver";
import { getSentryExpoConfig } from "@sentry/react-native/metro";
import { mergeConfig, type MetroConfig } from "metro-config";
import { existsSync, readdirSync, statSync } from "node:fs";
import path from "node:path";
const sentryConfig = getSentryExpoConfig(__dirname, { annotateReactComponents: true });
const { assetExts: assetExtensions = [], sourceExts: sourceExtensions = [] } = sentryConfig.resolver ?? {};
const customConfig: MetroConfig = {
resolver: {
assetExts: assetExtensions.filter((extension) => extension !== "svg"),
sourceExts: [...sourceExtensions, "svg"],
unstable_enablePackageExports: false
},
transformer: {
babelTransformerPath: require.resolve("react-native-svg-transformer")
}
};
const watchFolders = [
...new Set(
readdirSync(workspaceRoot)
.filter((fileName) => !["dist", "e2e"].includes(fileName) && !fileName.startsWith("."))
.map((fileName) => path.join(workspaceRoot, fileName))
.filter((filePath) => statSync(filePath).isDirectory())
)
].filter((folder) => existsSync(folder));
const nxConfig: MetroConfig = {
resolver: {
nodeModulesPaths: [path.join(workspaceRoot, "node_modules")],
resolveRequest: getResolveRequest(["", "ts", "tsx", "js", "jsx", "json"], [], [])
},
watchFolders
};
module.exports = mergeConfig(mergeConfig(sentryConfig, customConfig), nxConfig);
Observations
I tried everything to reproduce the error locally but I can't :
- Tried downgrading NodeJs version to use the default of EAS Workflows (18.18.0)
- Tried to create a script the reproduce the code present here : https://github.com/expo/eas-build/blob/main/packages/build-tools/src/steps/functions/repack.ts
- Tried to delete my .ts file to use only
metro.config.js, same error in EAS Workflows - In local, everything works perfectly
Managed or bare?
managed
Environment
expo-env-info 1.2.1 environment info:
System:
OS: macOS 26.1
Shell: 5.9 - /bin/zsh
Binaries:
Node: 24.11.1 - ~/.nvm/versions/node/v24.11.1/bin/node
Yarn: 1.22.22 - /opt/homebrew/bin/yarn
npm: 8.19.4 - ~/code/yonitou/hygo/node_modules/.bin/npm
Watchman: 2025.03.10.00 - /opt/homebrew/bin/watchman
SDKs:
iOS SDK:
Platforms: DriverKit 25.1, iOS 26.1, macOS 26.1, tvOS 26.1, visionOS 26.1, watchOS 26.1
IDEs:
Android Studio: 2025.1 AI-251.26094.121.2513.14007798
Xcode: 26.1.1/17B100 - /usr/bin/xcodebuild
npmPackages:
babel-preset-expo: ~54.0.0 => 54.0.7
expo: ^54.0.0 => 54.0.25
react: 19.1.0 => 19.1.0
react-dom: 19.1.0 => 19.1.0
react-native: 0.81.5 => 0.81.5
npmGlobalPackages:
eas-cli: 16.28.0
Expo Workflow: managed
Error output
Error: Found config at /Users/expo/workingdir/build/apps/mobile/metro.config.js that could not be
loaded with Node.js.
at loadConfigFile (/Users/expo/workingdir/build/apps/mobile/node_modules/@expo/metro/node_modu
les/metro-config/src/loadConfig.js:263:15)
at resolveConfig (/Users/expo/workingdir/build/apps/mobile/node_modules/@expo/metro/node_modul
es/metro-config/src/loadConfig.js:94:10)
at loadMetroConfigAsync (/Users/expo/workingdir/build/apps/mobile/node_modules/@expo/cli/src/s
tart/server/metro/instantiateMetro.ts:97:21)
Reproducible demo or steps to reproduce from a blank project
- Create a new expo app
- Create this custom build configuration
build:
name: Run tests
steps:
- eas/checkout
- eas/download_build:
id: download_build
inputs:
build_id: ${{ env.BUILD_ID }}
- eas/repack:
id: repack
inputs:
platform: ${{ env.PLATFORM }}
source_app_path: ${{ steps.download_build.outputs.artifact_path }}
- eas/upload_artifact:
id: upload_artifact
inputs:
path: ${{ steps.repack.outputs.output_path }}
- Create this EAS Workflows config file :
name: e2e-test
on:
pull_request:
defaults:
tools:
node: 22.12.0
jobs:
ios_repack:
id: ios_repack
type: build
params:
platform: ios
profile: e2e-tests-repack
env:
PLATFORM: ios
BUILD_ID: PUT_BUILD_ID_HERE
- Create this
metro.config.tsfile:
import { getSentryExpoConfig } from "@sentry/react-native/metro";
import { mergeConfig, type MetroConfig } from "metro-config";
import { existsSync, readdirSync, statSync } from "node:fs";
import path from "node:path";
const sentryConfig = getSentryExpoConfig(__dirname, { annotateReactComponents: true });
const { assetExts: assetExtensions = [], sourceExts: sourceExtensions = [] } = sentryConfig.resolver ?? {};
const customConfig: MetroConfig = {
resolver: {
assetExts: assetExtensions.filter((extension) => extension !== "svg"),
sourceExts: [...sourceExtensions, "svg"],
unstable_enablePackageExports: false
},
transformer: {
babelTransformerPath: require.resolve("react-native-svg-transformer")
}
};
module.exports = mergeConfig(sentryConfig, customConfig);
- Create this
metro.config.jsfile
require("tsx/cjs");
module.exports = require("./metro.config.ts");
- Create a pull request and look at the logs
Metadata
Metadata
Assignees
Labels
needs reviewIssue is ready to be reviewed by a maintainerIssue is ready to be reviewed by a maintainer