Skip to content

Fix nested @catch: stop inner-handled errors from propagating#5341

Open
christiansany wants to merge 2 commits into
facebook:mainfrom
christiansany:bug/nested-catch-always-triggers-outer-when-error-inside-inner
Open

Fix nested @catch: stop inner-handled errors from propagating#5341
christiansany wants to merge 2 commits into
facebook:mainfrom
christiansany:bug/nested-catch-always-triggers-outer-when-error-inside-inner

Conversation

@christiansany

Copy link
Copy Markdown
Contributor

Fixes #5339

The bug

When @catch directives are nested, a field error handled by the inner @catch is also counted by the outer @catch, so the outer boundary fires even though, from its perspective, the inner field resolved successfully.

  • @catch(to: RESULT): the outer field becomes { ok: false } instead of { ok: true, value: … }.
  • @catch(to: NULL): the whole outer object is nulled instead of just the inner field.

It compiles fine and fails silently at runtime. Full write-up and a runnable reproduction are in the linked issue (repro: christiansany/relay-playground#1).

The fix

In RelayReader, whether a @catch boundary "saw" an error was based on _fieldErrors being non-empty — but that list also contains errors already marked handled by an inner @catch (they flow through only for logging). The fix excludes already-handled errors when deciding an outer boundary's outcome:

  • _asResult now builds its result from the unhandled errors only ({ ok: true } when none remain).
  • The NULL path nulls the field only when there is an unhandled error (_fieldErrors.some(e => !e.handled)).

An inner @catch consumes its error and the outer boundary no longer reacts to it. Errors that are genuinely unhandled at a given level still propagate exactly as before.

Tests

Added regression tests in RelayReader-CatchFields-test.js covering both targets with a server error on the inner field:

  • nested @catch(to: RESULT) → outer me is { ok: true, value: { lastName: { ok: false, … } } } (inner catches, outer succeeds).
  • nested @catch(to: NULL){ me: { lastName: null } } (only the inner field nulled).

In both cases the error is still surfaced once in fieldErrors with handled: true.

Testing

  • New tests pass; existing RelayReader-CatchFields tests remain green.
  • Runtime-only change in RelayReader.js (10 lines); no API or compiler changes.

@meta-cla meta-cla Bot added the CLA Signed label Jun 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Nested @catch: an error handled by an inner @catch incorrectly propagates to the outer @catch

1 participant