facebook / facebook/relay

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
#4,146 6 comments 3 reactions 0 assignees View on GitHub
bug
Dominant language
Rust
Stars
19k
Forks
1.9k
PR merge metrics
No merged PRs in 30d

Description

> **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](https://codesandbox.io/s/react-18-relay-error-handling-rqbtno) 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](https://user-images.githubusercontent.com/721323/205564124-d1bc1f38-97fc-4e04-8b77-93b67d67bc29.png)

## Observed behaviour

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

![image](https://user-images.githubusercontent.com/721323/205564231-929146f3-b955-4d51-95aa-ca69d167b7ad.png)

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](https://codesandbox.io/s/react-18-relay-error-handling-rqbtno)

> React: 18.2.0
> Relay: 14.1.0
> Concurrent Mode: disabled

## ❌ [React 17, Relay 14.1](https://codesandbox.io/s/react-17-relay-error-handling-bnd8d2)

> 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](https://codesandbox.io/s/react-18-relay-error-handling-relay-11-4h5yr7)

> 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](https://codesandbox.io/s/react-18-relay-error-handling-rqbtno)

> 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](https://codesandbox.io/s/react-18-relay-error-handling-concurrent-mode-0gp3nw)

> 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](https://codesandbox.io/s/react-18-relay-error-handling-no-fragment-e5zo7j)

> 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](https://codesandbox.io/s/react-18-relay-error-handling-network-only-8l10ys)

> React: 18.2.0
> Relay: 14.1.0
> Concurrent Mode: disabled

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

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.