relay icon indicating copy to clipboard operation
relay copied to clipboard

Network errors not caught by error boundary when using `useLazyLoadQuery`, `useFragment` and a `store-and/or-network` fetch policy in non-concurrent mode (and React Native)

Open levibuzolic opened this issue 1 year ago • 5 comments

Note: I originally opened this issue as being React Native specific, however after testing in React DOM v17, this appears to be an issue common to all version of React running in non-concurrent mode (ie. ReactDOM.render) and all versions of React Native (which doesn't support concurrent mode prior to the new architecture).

This issue happens when using useLazyLoadQuery with a fetch policy of store-and-network or store-or-network and the data requiring network is specified in a useFragment. If a network error is raised, rather than being caught by the closest error boundary the component will instead render to completion without it's required data, violating the type safety contracts. In production environments this results in JS level errors as the rendered components try and access data that isn't present.

I've created a minimal reproduction in a CodeSandbox where the network layer intentionally throws an Error to simulate the behaviour of a failing fetch/error response.

React: 18.2.0 Relay: 14.1.0 Concurrent Mode: disabled

Expected behaviour

The network error should halt the component render, and the network error should bubble up to be caught by the closest error boundary component.

image

Observed behaviour

The network error is ignored and the component renders to completion. This results in JS TypeErrors as the component will try and access data that is expected to be present. This breaks the type safety contract.

image

Curiously if you trigger another render in the component (e.g. by setting state) the error will then be correctly handled, it's only on the initial render that the error is ignored.

Other test cases

❌  = bug is present
✅  = correct behaviour

React 18, Relay 14.1 - concurrent mode disabled

React: 18.2.0 Relay: 14.1.0 Concurrent Mode: disabled

React 17, Relay 14.1

React: 17.0.2 Relay: 14.1.0

React 17 doesn't support concurrent mode, so it exhibits the same issue.

React 18.2, Relay 11 - concurrent mode disabled

React: 18.2.0 Relay: 11.0.2 Concurrent Mode: disabled

This issue appears to be present in all versions of Relay hooks (>=11.0.0)

React 18, Relay nightly 0.0.0-main-f8ccd9af - concurrent mode disabled

React: 18.2.0 Relay: 0.0.0-main-f8ccd9af f8ccd9af Concurrent Mode: disabled

Issue is present in the latest published nightly (as of December 23rd, 2022)

React 18 - Concurrent mode enabled

React: 18.2.0 Relay: 14.1.0 Concurrent Mode: enabled

With concurrent mode enabled, the network error is successfully caught by the parent error boundary component.

React 18 - without fragment - concurrent mode disabled

React: 18.2.0 Relay: 14.1.0 Concurrent Mode: disabled

If we omit the useFragment and instead define the data requirements entirely within the useLazyLoadQuery, the network error is handled correctly.

fetchPolicy: 'network-only' - concurrent mode disabled

React: 18.2.0 Relay: 14.1.0 Concurrent Mode: disabled

When using fetchPolicy: 'network-only' the error is handled correctly.

levibuzolic avatar Dec 03 '22 11:12 levibuzolic