---
title: Error handling | Qwik Router
contributors:
  - DustinJSilk
updated_at: '2025-01-11T18:00:00Z'
created_at: '2025-01-11T18:00:00Z'
---

import { Note } from '~/components/note/note';

# Error handling

When an error is thrown in a loader or `server$` function, a 500 error is returned to the client along with the error. This is useful during development but isn't always desirable for production systems. Qwik provides the tools necessary to customise how errors are handled.

Throwing a `ServerError` instance allows you to return custom errors to the browser with a different status code and serialised data.

<Note>Loaders also provide a helper function on the event object to easily create new ServerErrors.</Note>

```tsx
// Throw ServerErrors from a routerLoader$
const useProduct = routeLoader$(async (ev) => {
  const product = await fetch('api/product/1')

  if (!product) {
    // Throw a 404 with a custom payload
    throw new ServerError(404, 'Product not found')

    // Or use the existing helper function
    throw ev.error(404, 'Product not found')
  }

  return product
})

// Throw ServerErrors from a server$
const getPrices = server$(() => {
  if (!isAuthenticated()) {
    throw new ServerError(401, { code: 401 })
  }

  return fetch('api/product/1/prices')
})

export default component$(() => {
  const product = useProduct()

  useVisibleTask(() => {
    getPrices()
      .then()
      .catch(err => {
        // The payload from a ServerError is deserialised as the error caught in the client
        if (err.code === 401) {
          // Navigate to login page
        }

        // Show generic error
      })
  })

  return <div>Product page</div>
})
```

## Error interceptor

Intercepting errors with middleware has a few usecases: you might want to hide error details in production systems, add structured error logging, or map the error status codes from RPC API calls to HTTP status codes. This is all achieveable with middleware in a `plugin` file.

```tsx
// src/routes/plugin@errors.ts
import { type RequestHandler } from '@qwik.dev/router'
import { RedirectMessage, ServerError } from '@qwik.dev/router/middleware/request-handler'
import { isDev } from '@qwik.dev/core/build'

export const onRequest: RequestHandler = async ({ next }) => {
  try {
    return await next();
  } catch (err) {
    // Pass through 3xx redirects
    if (err instanceof RedirectMessage) {
      throw err
    }

    // Pass through ServerErrors
    if (err instanceof ServerError) {
      throw err
    }

    // Log unknown errors
    console.error('unknown error', err)

    if (isDev) {
      throw err
    } else {
      throw new ServerError(500, 'Internal server error');
    }
  }
};



```
