After a React Native upgrade, what symptoms show that a library still relies on legacy-architecture APIs, and how do you trace each symptom to its cause?
answer
- build time versus run time
- removed Android classes, 0.84 and 0.85
- iOS legacy code compiled out in 0.84
- 'not available in the new architecture'
- bridge proxy returns nil, logs unsupported
basics
~20 sLegacy dependence shows as Android compile errors on classes removed in 0.84 or 0.85, iOS build failures now that legacy code is compiled out, 'not available in the new architecture' errors, nil-returning bridge-proxy calls and Unimplemented component placeholders.
solid answer
~50 sI sort symptoms into **build time** and **run time**. At build time, Android errors on unresolved classes such as `CatalystInstanceImpl` (removed in 0.85) or `LazyReactPackage` and `OnBatchCompleteListener` (removed in 0.84) point at a library compiled against the Legacy Architecture; on iOS, since 0.84 legacy code is compiled out, so code needing those symbols fails to build. At run time, JavaScript logs `'<method>' is not available in the new React Native architecture` for Paper-only `UIManager` calls, a legacy iOS module touching its `bridge` gets a proxy that logs "This method is unsupported" and returns nil, and a missing native view shows `Unimplemented component: <Name>`. The trace is the same each time: follow the file path in the error or stack to the package under `node_modules`, check its releases, then update, replace, fork or port it. The iOS legacy code can be re-included only as a from-source stopgap.
code
bash · 5 lines# Find which dependency references a class removed in React Native 0.85
grep -rl "CatalystInstanceImpl" node_modules/*/android node_modules/@*/*/android
# Find Paper-only UIManager calls in JavaScript dependencies
grep -rlE "UIManager\.(createView|updateView|manageChildren|setChildren)" node_modules --include="*.js"go deeper
Recognise that errors mentioning the new React Native architecture, or placeholders naming an unimplemented component, point at an incompatible library rather than your own screen code.
Map each symptom to its layer: removed native classes at build time, Paper-only UIManager calls and bridge-proxy warnings at run time, placeholders for unregistered views.
Trace systematically from the path in the error to the package, confirm the API, check upstream and decide, and hunt the silent iOS bridge-proxy failures that do not crash.
Make legacy-API log checks a gate in every upgrade, and set a firm expiry on any from-source legacy stopgap so it cannot quietly become the platform.
## Why symptoms appear after an upgrade React Native 0.82 made the New Architecture mandatory without removing legacy APIs. From **0.84** on, the team has been deleting Legacy Architecture code in every release: iOS builds compile it out by default and Android loses legacy classes. A library that leaned on those pieces worked yesterday through interop or leftover code, and after the upgrade it fails, sometimes loudly and sometimes silently. ## Build-time symptoms - **Android: unresolved legacy classes.** 0.84 removed a list including `LazyReactPackage`, `CxxModuleWrapper`, `CallbackImpl`, `OnBatchCompleteListener` and `LayoutAnimationController`; 0.85 removed `CatalystInstanceImpl`, deprecated `UIManagerHelper` and stubbed out `NativeViewHierarchyManager`. A compile error naming one of these, in a file under a library's directory, identifies the culprit precisely. - **iOS: missing legacy symbols.** Since 0.84 `RCT_REMOVE_LEGACY_ARCH` is on by default, so Objective-C code that depends on legacy-only classes no longer compiles or links. As a stopgap, legacy code can be re-included by building React Native from source with `RCT_USE_PREBUILT_RNCORE=0 RCT_REMOVE_LEGACY_ARCH=0` at `pod install`, at the cost of the precompiled binaries' build speed. ## Run-time symptoms | Symptom | Where you see it | What it means | |---|---|---| | `'<method>' is not available in the new React Native architecture.` | JavaScript console | Code called a Paper-only `UIManager` method (`createView`, `updateView`, `setChildren`, `manageChildren`, `setJSResponder`, `clearJSResponder`), which now does nothing | | "This method is unsupported. Returning nil." | iOS native log | A legacy module used its `bridge`, which is now a proxy; for example `delegate` returns nil and `enqueueCallback` is a no-op | | `Unimplemented component: <Name>` | On screen, iOS | Fabric found neither a Fabric component nor a legacy view manager for that name | | DevTools warnings about legacy APIs | React Native DevTools | Since 0.80, APIs that will not work on the New Architecture are flagged | | Deprecation warnings (for example `ViewUtil.getUIManagerType`, deprecated in 0.86) | Build or runtime logs | Code still branching on the old renderer; it will break in a later release | The bridge-proxy case deserves attention because it is **silent**: nothing crashes, a value is simply nil, and a feature (say, a ride-status callback) quietly stops working. ## Tracing a symptom to its cause 1. **Read the path.** Compile errors and JavaScript stack traces name a file; a path under `node_modules/<package>` names the library. 2. **Confirm the API.** Search that package's source for the class or method in the message. 3. **Check upstream.** Look for a release that migrated the library, a stated minimum React Native version, or an open issue. 4. **Decide.** Update if a fixed version exists; otherwise replace, fork or port, and record the decision. 5. **Re-test the flow** that exposed it, on both platforms, in a release build. ## A worked example A ride-hailing team bumps React Native to 0.85: 1. The Android build stops with an unresolved `CatalystInstanceImpl` in a file under a trip-sharing library's `android/` folder. The class was removed in 0.85, so the library is compiled against legacy internals; its changelog shows a newer major version that dropped the reference, and upgrading fixes the build. 2. The iOS build succeeds, but in testing the live ride-status banner never updates. The native log shows the bridge proxy reporting that `enqueueCallback` is not supported. The status library's iOS module still pushes results through the old bridge's callback path, which is now a no-op. 3. No fixed release exists, so the team records it as broken, moves the banner to a maintained alternative and adds the flow to its upgrade test list. Neither failure needed guesswork: each message carried a path or a method name that led to one package. ## Mistakes to avoid - **Silencing the log instead of fixing the call.** The Paper-only methods are no-ops; the feature is broken whether or not you see the message. - **Reaching for an architecture opt-out.** `newArchEnabled=false` and `RCT_NEW_ARCH_ENABLED=0` are ignored since 0.82. - **Treating the from-source iOS stopgap as permanent.** It keeps one release working; later releases keep removing legacy code. - **Blaming React Native for an unlinked library.** An `Unimplemented component` placeholder usually means the native side is not in the build. ## Summary Legacy dependence surfaces as compile errors on removed classes, soft JavaScript errors from Paper-only `UIManager` methods, nil results from the iOS bridge proxy, and placeholder views. Every one of them carries a file path or a component name that leads to a specific library and a decision about it.
- Why is a bridge-proxy warning on iOS more dangerous than an Android compile error?A compile error stops the build, so nobody ships it. The iOS bridge proxy lets the app run: an unsupported method logs a message and returns nil or does nothing, so a feature silently fails in production. It needs log review and flow testing to catch, which is why runtime logs are part of every upgrade test.
- When is re-including legacy iOS code from source acceptable?As a short, dated stopgap to ship one release while a blocking library is updated or replaced. It requires building React Native from source (`RCT_USE_PREBUILT_RNCORE=0 RCT_REMOVE_LEGACY_ARCH=0`), which gives up the precompiled binaries' faster builds, and each later release removes more legacy code, so the stopgap only buys time.
saying these in an interview costs you the question
- A soft UIManager error is harmless because the app did not crash
- Setting RCT_NEW_ARCH_ENABLED=0 fixes legacy symbol errors on iOS
- Every legacy dependency announces itself with a crash
- An Unimplemented component placeholder always means an outdated library
- The from-source legacy iOS build is a permanent solution