Skip to content

uniwind-pro@1.1.3 crashes Hermes with "Maximum call stack size exceeded (native stack depth)" on iOS at runtime init (1.1.2 works) #540

Description

@antoinerousseau

What happened?

Bug summary

Upgrading uniwind-pro from 1.1.21.1.3 causes the app to crash immediately when the JS bundle starts evaluating on iOS / Hermes, before AppRegistry.registerComponent is reached. Pinning back to uniwind-pro@1.1.2 (no other changes) resolves the crash.

The bundle compiles successfully — the crash is at runtime during the bridgeless boot sequence:

iOS Bundled 12595ms apps/backstage/index.ts (5570 modules)
[React] [runtime not ready]: RangeError: Maximum call stack size exceeded (native stack depth)
[React] [runtime not ready]: RangeError: Maximum call stack size exceeded (native stack depth)
[React] [runtime not ready]: Invariant Violation: "main" has not been registered. This can happen if:
* Metro (the local dev server) is run from the wrong folder. Check if Metro is running, stop it and restart it in the current project.
* A module failed to load due to an error and `AppRegistry.registerComponent` wasn't called.

The "main" has not been registered line is a downstream consequence — JS evaluation aborts on the stack overflow, so expo-router/entry never registers the root component.

The error reports (native stack depth), which is Hermes' C++ runtime running out of native stack during module initialization (not a JS-level infinite loop).

Environment

uniwind-pro (broken) 1.1.3
uniwind-pro (working) 1.1.2
expo ~55.0.24
react-native 0.83.8
react 19.2.6
react-native-nitro-modules 0.35.6
react-native-reanimated 4.3.1
react-native-worklets 0.8.3
Architecture New Architecture / Bridgeless / Hermes
Package manager pnpm@11.1.1 (workspace monorepo, publicHoistPattern: "*")
Node v24.15.0
macOS 26.4.1
Xcode 26.5
CocoaPods 1.16.2

metro.config.js:

const { getSentryExpoConfig } = require("@sentry/react-native/metro");
const { withUniwindConfig } = require("uniwind/metro");
const path = require("path");

const config = getSentryExpoConfig(__dirname);

config.resolver.sourceExts.push("sql");
config.resolver.blockList = [
  /\/apps\/backstage-server\/.*/,
  /\/apps\/api\/.*/,
  /\/.turbo\/.*/,
];
config.resolver.nodeModulesPaths = [
  ...config.resolver.nodeModulesPaths,
  path.resolve(__dirname, "modules"),
];
config.resolver.unstable_enablePackageExports = true;

module.exports = withUniwindConfig(config, {
  cssEntryFile: "./src/global.css",
  debug: typeof __DEV__ === "boolean" ? __DEV__ : false,
});

babel.config.js:

module.exports = function (api) {
  api.cache(true);
  return {
    presets: [["babel-preset-expo", { unstable_transformImportMeta: true }]],
    plugins: [
      ["inline-import", { extensions: [".sql"] }],
      "react-native-worklets/plugin",
    ],
  };
};

App entry (index.ts):

import "~/libs/logs";
import "~/libs/polyfills"; // @formatjs/intl-pluralrules
import "~/libs/netinfo";
import "expo-router/entry";

src/global.css:

@import "tailwindcss";
@import "uniwind";
@import "../node_modules/@shotgun/decibel/dist/themes/backstage.css";

Notes / possible angles

The 1.1.3 changelog lists changes that look adjacent to bundle / runtime initialization, particularly:

  • Metro variable dependency fix — "Added missing variable metro dependency to the C++ side so CSS variable updates resolve correctly"
  • Cache wipe on CSS variables update
  • Deeply themed variables fix — "Fixed lookup for deeply nested themed variables"

Speculating: if the new Metro transform / C++ wiring emits a deeply nested object literal or recurses through themed variables at module init, it could plausibly blow the native Hermes stack during bundle eval.

Workaround

Pin uniwind-pro to 1.1.2:

"dependencies": {
  "uniwind": "npm:uniwind-pro@1.1.2"
}

Steps to Reproduce

In an Expo SDK 55 / RN 0.83.8 / new-arch / bridgeless app using uniwind-pro, change only the version:

- "uniwind": "npm:uniwind-pro@^1.1.2"
+ "uniwind": "npm:uniwind-pro@^1.1.3"

Then pnpm install and pnpm expo run:ios.
Steps I took to rule out cache/build artifact issues (all reproduced the crash with 1.1.3):

  1. pkill Metro / dev-client processes
  2. watchman watch-del-all and removed Metro / Watchman caches from $TMPDIR
  3. Removed .expo, node_modules/.cache, ios/build, and Xcode DerivedData
  4. expo prebuild --clean --platform ios (gitignored /ios, regenerated from scratch)
  5. Fresh pod install
  6. Fresh expo run:ios (full native compile from scratch, no ccache hits)
    → Same crash. Reverting only uniwind-pro to 1.1.2 (with everything else identical) fixes it.

Snack or Repository Link (Optional)

No response

Uniwind version

pro 1.1.3

React Native Version

0.83.8

Platforms

iOS

Expo

Yes

Additional information

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions