Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/tanstack/router/llms.txt

Use this file to discover all available pages before exploring further.

TanStack Router provides robust error handling through error boundaries that catch and display errors from loaders, components, and navigation.

Error components

Define custom error boundaries at route level:
import { createFileRoute, ErrorComponent } from '@tanstack/react-router'

export const Route = createFileRoute('/posts/$postId')({
  loader: async ({ params }) => {
    const post = await fetchPost(params.postId)
    if (!post) throw new Error('Post not found')
    return { post }
  },
  errorComponent: PostErrorComponent,
})

function PostErrorComponent({ error, reset }: ErrorComponentProps) {
  return (
    <div className="error-container">
      <h2>Error Loading Post</h2>
      <p>{error.message}</p>
      <button onClick={reset}>Try Again</button>
    </div>
  )
}

Error component props

Error components receive helpful props:
import type { ErrorComponentProps } from '@tanstack/react-router'

function MyErrorComponent({ error, info, reset }: ErrorComponentProps) {
  // error - The thrown error
  console.error(error)
  
  // info - React error boundary info
  console.log(info?.componentStack)
  
  // reset - Function to retry/reset the error boundary
  const handleRetry = () => {
    reset()
  }
  
  return (
    <div>
      <h1>Something went wrong</h1>
      <pre>{error.message}</pre>
      <button onClick={handleRetry}>Retry</button>
    </div>
  )
}

Root error boundary

Catch errors from all routes:
import { createRootRoute, ErrorComponent } from '@tanstack/react-router'

export const Route = createRootRoute({
  errorComponent: RootErrorComponent,
  component: RootComponent,
})

function RootErrorComponent({ error, reset }: ErrorComponentProps) {
  return (
    <html>
      <body>
        <div>
          <h1>Application Error</h1>
          <p>{error.message}</p>
          <button onClick={reset}>Reset Application</button>
        </div>
      </body>
    </html>
  )
}

Throwing errors in loaders

Throw errors during data loading:
export const Route = createFileRoute('/posts/$postId')({
  loader: async ({ params }) => {
    const post = await fetchPost(params.postId)
    
    if (!post) {
      throw new Error('Post not found')
    }
    
    if (!post.published) {
      throw new Error('This post is not published yet')
    }
    
    return { post }
  },
})

Custom error types

Create typed errors for better handling:
class NotFoundError extends Error {
  constructor(resource: string) {
    super(`${resource} not found`)
    this.name = 'NotFoundError'
  }
}

class UnauthorizedError extends Error {
  constructor() {
    super('You are not authorized to view this resource')
    this.name = 'UnauthorizedError'
  }
}

export const Route = createFileRoute('/posts/$postId')({
  loader: async ({ params, context }) => {
    if (!context.auth.isAuthenticated) {
      throw new UnauthorizedError()
    }
    
    const post = await fetchPost(params.postId)
    if (!post) {
      throw new NotFoundError('Post')
    }
    
    return { post }
  },
  errorComponent: ({ error, reset }) => {
    if (error instanceof UnauthorizedError) {
      return <Navigate to="/login" />
    }
    
    if (error instanceof NotFoundError) {
      return (
        <div>
          <h2>404 - {error.message}</h2>
          <Link to="/">Go Home</Link>
        </div>
      )
    }
    
    return (
      <div>
        <h2>Unexpected Error</h2>
        <p>{error.message}</p>
        <button onClick={reset}>Try Again</button>
      </div>
    )
  },
})

Component errors

Error boundaries also catch component errors:
function PostComponent() {
  const { post } = Route.useLoaderData()
  
  // This error will be caught by errorComponent
  if (!post.content) {
    throw new Error('Post has no content')
  }
  
  return <article>{post.content}</article>
}

Resetting errors

The reset function retries the failed operation:
function ErrorComponent({ error, reset }: ErrorComponentProps) {
  const [retryCount, setRetryCount] = React.useState(0)
  
  const handleRetry = () => {
    setRetryCount((c) => c + 1)
    reset()
  }
  
  return (
    <div>
      <p>Error: {error.message}</p>
      <p>Retry attempts: {retryCount}</p>
      <button onClick={handleRetry}>Try Again</button>
    </div>
  )
}

Default error component

Use the built-in error component:
import { ErrorComponent } from '@tanstack/react-router'

export const Route = createFileRoute('/posts/$postId')({
  errorComponent: ErrorComponent,
})

Not found errors

Handle 404 errors separately:
import { notFound } from '@tanstack/react-router'

export const Route = createFileRoute('/posts/$postId')({
  loader: async ({ params }) => {
    const post = await fetchPost(params.postId)
    if (!post) throw notFound()
    return { post }
  },
  notFoundComponent: () => (
    <div>
      <h1>Post Not Found</h1>
      <Link to="/posts">View All Posts</Link>
    </div>
  ),
})

Error logging

Log errors to external services:
import * as Sentry from '@sentry/react'

function GlobalErrorComponent({ error, info }: ErrorComponentProps) {
  React.useEffect(() => {
    Sentry.captureException(error, {
      extra: {
        componentStack: info?.componentStack,
      },
    })
  }, [error, info])
  
  return <div>An error occurred. Our team has been notified.</div>
}

Best practices

Give users context about what went wrong and how to recover.
Allow users to retry failed operations.
Create custom error classes for better error handling and recovery.
Integrate with error tracking services like Sentry or LogRocket.

Next steps

Data loading

Learn about loader error handling

Route API

Explore error configuration options