From 31bee3dd5acb218493f23c550f9c5563d008e3b6 Mon Sep 17 00:00:00 2001 From: Pieter De Baets Date: Thu, 16 Jul 2026 12:52:26 -0700 Subject: [PATCH] Allow arbitrary values in ReactCxxPlatform NativeExceptionsManager extraData MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: The JS-side `ExceptionData.extraData` field is spec'd as `?Object` — an arbitrarily-nested plain object whose values can be numbers, sub-objects, arrays, etc. Callers routinely populate it that way: `ExceptionsManager.js` adds `jsEngine`/`rawStack` plus Hermes-style `stackSymbols`/`stackReturnAddresses`/`stackElements`, decorators can attach `jsBuild` as a number, and any `Error` with a decorated `RN$ErrorExtraDataKey` may contribute nested objects. The ReactCxxPlatform NativeExceptionsManager modeled that field as `std::optional>`, forcing every value to be a string. As soon as a caller included a non-string value the JSI bridging layer threw `Value is an object, expected a String` *before* `reportException` even ran, so the JS `.catch` handler that issued the report unwound its remaining synchronous work — including any `onComplete` callback that follows the report call. Relax the C++ spec to `std::optional` to match the JS `?Object` type. `reportException` doesn't currently forward `extraData` into the JsErrorHandler, so no downstream code needs updating. Changelog: [Internal] Differential Revision: D112388436 --- .../react/logging/NativeExceptionsManager.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/react-native/ReactCxxPlatform/react/logging/NativeExceptionsManager.h b/packages/react-native/ReactCxxPlatform/react/logging/NativeExceptionsManager.h index 4dba94aa3f0a..9e8d49ac8c2f 100644 --- a/packages/react-native/ReactCxxPlatform/react/logging/NativeExceptionsManager.h +++ b/packages/react-native/ReactCxxPlatform/react/logging/NativeExceptionsManager.h @@ -8,11 +8,11 @@ #pragma once #include +#include #include #include #include #include -#include #include #include @@ -29,6 +29,11 @@ using StackFrame = NativeExceptionsManagerStackFrame< template <> struct Bridging : NativeExceptionsManagerStackFrameBridging {}; +// extraData is `?Object` on the JS side and callers routinely populate it with +// non-string values (e.g. jsBuild as a number, nested Error-decorated objects +// via RN$ErrorExtraDataKey). A flat unordered_map would fail +// bridging with "Value is an object, expected a String" before reportException +// runs. using ExceptionData = NativeExceptionsManagerExceptionData< std::string, std::optional, @@ -37,7 +42,7 @@ using ExceptionData = NativeExceptionsManagerExceptionData< std::vector, int32_t, bool, - std::optional>>; + std::optional>; template <> struct Bridging : NativeExceptionsManagerExceptionDataBridging {};