Skip to content

Fix DimensionValue props crashing ViewManagers on Android - #58039

Closed
dennytosp wants to merge 1 commit into
react:mainfrom
dennytosp:fix/dimension-react-prop-setter
Closed

Fix DimensionValue props crashing ViewManagers on Android#58039
dennytosp wants to merge 1 commit into
react:mainfrom
dennytosp:fix/dimension-react-prop-setter

Conversation

@dennytosp

Copy link
Copy Markdown
Contributor

Summary:

A Fabric component whose spec declares a DimensionValue prop:

type NativeProps = Readonly<{
  ...ViewProps,
  marginBack?: DimensionValue,
}>;

crashes the app while React Native is collecting view manager constants, as soon
as the ViewManager implements that prop with @ReactProp:

java.lang.RuntimeException: Unrecognized type: class com.facebook.yoga.YogaValue
  for method: MyNativeViewManager#setMarginBack
  at ViewManagersPropertyCache.createPropSetter(...)
  at ViewManagerPropertyUpdater$FallbackViewManagerSetter.<init>(...)
  at ViewManager.getNativeProps(...)
  at UIManagerModuleConstantsHelper.internal_createConstantsForViewManager(...)

Root cause

Codegen maps DimensionValue to the DimensionPrimitive reserved type and emits
a boxed @Nullable YogaValue setter on the generated ViewManager interface — this
is covered by a committed snapshot:

// GeneratePropsJavaInterface-test.js.snap
public interface DimensionPropNativeComponentManagerInterface<T extends View> extends ViewManagerWithGeneratedInterface {
  void setMarginBack(T view, @Nullable YogaValue value);
}

ViewManagersPropertyCache.createPropSetter has no branch for YogaValue, so it
falls through to the else and throws.

The conversion logic already exists — DimensionPropConverter handles exactly the
three shapes a DimensionValue arrives in (null, a Double in points, a String
like "100%") and has its own unit tests. But it is only referenced by generated
delegate code (GeneratePropsJavaDelegate.js), never by the @ReactProp path.
Compare ColorPropConverter, which is wired into both paths — that asymmetry is
the bug.

This adds the missing DimensionPropSetter, modelled on ColorPropSetter, which
delegates wholesale to the existing converter. It reports mixed as its prop type
because a dimension may be a number or a string, matching how colors are reported.

Note the blast radius: getNativePropSettersForViewManagerClass builds the setter
map for an entire ViewManager class in one pass, so a single unbindable prop takes
down every other prop on that manager, and createConstantsForViewManager reads
viewManager.nativeProps unconditionally. That is why this surfaces as a startup
crash rather than a failure when the prop is first set.

This is the same class of gap as #55350 (@Nullable Float). With both fixed, every
Java type GeneratePropsJavaInterface can emit is bindable through @ReactProp.

Changelog:

[ANDROID] [FIXED] - Fix RuntimeException: Unrecognized type: class com.facebook.yoga.YogaValue when a ViewManager implements a DimensionValue prop with @ReactProp

Test Plan:

Added testDimensionSetter and testFailToUpdateDimensionPropWithArray to
ReactPropAnnotationSetterTest, plus a dimensionProp on the ViewManager under
test. They drive viewManager.updateProperties(...) — the same
FallbackViewManagerSetter -> getNativePropSettersForViewManagerClass ->
createPropSetter path as the crash — and assert the setter receives
YogaValue(10.5f, POINT) for a number, YogaValue(100f, PERCENT) for "100%",
and null for null, and that an unsupported value still surfaces as a
JSApplicationIllegalArgumentException rather than escaping raw.

$ ./gradlew :packages:react-native:ReactAndroid:testDebugUnitTest \
    --tests "com.facebook.react.uimanager.ReactPropAnnotationSetterTest"

BUILD SUCCESSFUL
tests=19 failures=0 errors=0
  ok testDimensionSetter                    <- new
  ok testFailToUpdateDimensionPropWithArray <- new
  ... (19/19)

Reverting only ViewManagersPropertyCache.kt and keeping the new tests reproduces
the crash:

tests=19 failures=19

java.lang.RuntimeException: Unrecognized type: class com.facebook.yoga.YogaValue
  for method: ReactPropAnnotationSetterTest$ViewManagerUnderTest#setDimensionProp

All 19 fail rather than only the two new ones, for the reason described above: the
setter map is built for the whole ViewManager class at once.

Formatting — ./gradlew ktfmtFormat leaves both changed files byte-identical.

ViewManagersPropertyCache is an internal object and DimensionPropSetter is a
private class, so ReactAndroid.api is unchanged.

Codegen maps a `DimensionValue` prop to the `DimensionPrimitive` reserved
type and emits a `@Nullable YogaValue` setter on the generated ViewManager
interface. If the ViewManager implements that setter with `@ReactProp`,
the app crashes while collecting view manager constants:

  RuntimeException: Unrecognized type: class com.facebook.yoga.YogaValue
    for method: MyNativeViewManager#setMarginBack

`ViewManagersPropertyCache.createPropSetter` has no branch for
`YogaValue`, so it falls through to the `else` and throws.

The conversion already exists: `DimensionPropConverter` handles the three
shapes a dimension arrives in (null, a Double in points, a String such as
"100%") and is unit tested. It was only ever wired into generated
delegate code, never into the `@ReactProp` path — unlike
`ColorPropConverter`, which is used by both.

Add the missing `DimensionPropSetter`, modelled on `ColorPropSetter`,
delegating to that converter. It reports `mixed` as its prop type since a
dimension may be a number or a string, matching how colors are reported.

This is the same class of gap as the `@Nullable Float` one. With both
closed, every Java type `GeneratePropsJavaInterface` can emit is bindable
through `@ReactProp`.
@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Aug 21, 2026
@facebook-github-tools facebook-github-tools Bot added the Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team. label Aug 21, 2026
@meta-codesync

meta-codesync Bot commented Aug 21, 2026

Copy link
Copy Markdown

@javache has imported this pull request. If you are a Meta employee, you can view this in D116911179.

@meta-codesync meta-codesync Bot closed this in 091ac61 Aug 21, 2026
@meta-codesync meta-codesync Bot added the Merged This PR has been merged. label Aug 21, 2026
@meta-codesync

meta-codesync Bot commented Aug 21, 2026

Copy link
Copy Markdown

@javache merged this pull request in 091ac61.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. Merged This PR has been merged. Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant