# Error Boundaries

In Neutron, errors don't have to crash your entire application. You can define Error Boundaries to catch errors within specific routes or layouts.

## The `ErrorBoundary` Component

Any route file can export an `ErrorBoundary` component.

```tsx
// src/routes/app/dashboard.tsx
import type { ErrorBoundaryProps } from "@neutron-build/core";

export default function Dashboard() {
  throw new Error("Something broke!");
}

// The nearest ErrorBoundary catches the error. It receives the thrown error
// as a prop, plus an optional `reset` to retry rendering.
export function ErrorBoundary({ error, reset }: ErrorBoundaryProps) {
  return (
    <div className="error">
      <h1>Oops!</h1>
      <p>{error.message}</p>
      {reset && <button onClick={reset}>Try again</button>}
    </div>
  );
}
```

## Granular Error Handling

Error boundaries operate hierarchically. If a route throws an error, Neutron looks for the nearest Error Boundary.

1.  **Route level**: `src/routes/app/dashboard.tsx` (exports `ErrorBoundary`)
2.  **Sibling level**: `src/routes/app/_error.tsx` (if the route file doesn't export one)
3.  **Parent Layout**: `src/routes/app/_layout.tsx`
4.  **Root**: `src/routes/_error.tsx`

This means if a specific part of your page crashes (e.g., a widget in the dashboard), the surrounding layout (sidebar, header) remains interactive. Only the broken part is replaced by the Error Boundary.

## Expected Errors (Throwing Responses)

To short-circuit a request with a specific HTTP response — a 404, a redirect, a permission error — throw a `Response` from a loader or action (the `notFound()` and `redirect()` helpers return one). Neutron serves it **directly as the HTTP response**; it does not render the `ErrorBoundary`.

```tsx
import { notFound, type LoaderArgs } from "@neutron-build/core";

export async function loader({ params }: LoaderArgs) {
  const project = await getProject(params.id);

  if (!project) {
    throw notFound(); // → 404 response, served as-is
  }

  return { project };
}
```

Throwing (or letting propagate) an `Error` — rather than a `Response` — is what triggers the nearest `ErrorBoundary`.
