examples/swr-site/content/en/docs/error-handling.mdx
import { Callout } from 'nextra/components'
If an error is thrown inside fetcher, it will be
returned as error by the hook.
const fetcher = url => fetch(url).then(r => r.json())
// ...
const { data, error } = useSWR('/api/user', fetcher)
The error object will be defined if the fetch promise is rejected.
Sometimes we want an API to return an error object alongside the status code. Both of them are useful for the client.
We can customize our fetcher to return more information. If the status code is
not 2xx, we consider it an error even if it can be parsed as JSON:
const fetcher = async url => {
const res = await fetch(url)
// If the status code is not in the range 200-299,
// we still try to parse and throw it.
if (!res.ok) {
const error = new Error('An error occurred while fetching the data.')
// Attach extra info to the error object.
error.info = await res.json()
error.status = res.status
throw error
}
return res.json()
}
// ...
const { data, error } = useSWR('/api/user', fetcher)
// error.info === {
// message: "You are not authorized to access this resource.",
// documentation_url: "..."
// }
// error.status === 403
Here we have an example.
SWR uses the exponential backoff algorithm to retry the request on error. The algorithm allows the app to recover from errors quickly, but not waste resources retrying too often.
You can also override this behavior via the onErrorRetry option:
useSWR('/api/user', fetcher, {
onErrorRetry: (error, key, config, revalidate, { retryCount }) => {
// Never retry on 404.
if (error.status === 404) return
// Never retry for a specific key.
if (key === '/api/user') return
// Only retry up to 10 times.
if (retryCount >= 10) return
// Retry after 5 seconds.
setTimeout(() => revalidate({ retryCount }), 5000)
}
})
This callback gives you the flexibility to retry based on various conditions.
You can also disable it by setting shouldRetryOnError: false.
It's also possible to provide it via the Global Configuration context.
You can always get the error object inside the component reactively. But in
case you want to handle the error globally, to notify the UI to show a
toast or a
snackbar, or report it somewhere
such as Sentry, there's an
onError event:
<SWRConfig
value={{
onError: (error, key) => {
if (error.status !== 403 && error.status !== 404) {
// We can send the error to Sentry,
// or show a notification UI.
}
}
}}
>
<MyApp />
</SWRConfig>