Обработка ошибок в Next.js

Next.js App Router использует файловую систему для обработки ошибок. Файлы error.tsx и not-found.tsx автоматически создают Error Boundaries на уровне каждого сегмента маршрута.

error.tsx

Файл error.tsx перехватывает ошибки в рантайме и показывает fallback UI вместо сломанной страницы:

'use client'

export default function Error({
  error,
  reset
}: {
  error: Error & { digest?: string }
  reset: () => void
}) {
  return (
    <div>
      <h2>Что-то пошло не так</h2>
      <p>{error.message}</p>
      <button onClick={() => reset()}>Попробовать снова</button>
    </div>
  )
}

Ключевые моменты:

  • error.tsx обязательно должен быть клиентским компонентом ('use client')
  • reset пытается заново отрендерить сегмент
  • error.digest содержит хеш ошибки для логирования на сервере

Вложенная обработка ошибок

Ошибки всплывают вверх к ближайшему error.tsx:

Ошибка в /problems/123 будет перехвачена app/problems/error.tsx. Если его нет, всплывет к app/error.tsx.

Важно:

error.tsx не перехватывает ошибки в layout.tsx того же сегмента, потому что error boundary вложен внутрь layout. Для обработки ошибок в layout нужен error.tsx в родительском сегменте.

global-error.tsx

Для обработки ошибок в корневом layout:

// app/global-error.tsx
'use client'

export default function GlobalError({
  error,
  reset
}: {
  error: Error & { digest?: string }
  reset: () => void
}) {
  return (
    <html>
      <body>
        <h2>Произошла критическая ошибка</h2>
        <button onClick={() => reset()}>Перезагрузить</button>
      </body>
    </html>
  )
}

global-error.tsx заменяет весь корневой layout, поэтому должен содержать <html> и <body>.

not-found.tsx

Для обработки 404 ошибок:

// app/not-found.tsx
import Link from 'next/link'

export default function NotFound() {
  return (
    <div>
      <h2>Страница не найдена</h2>
      <p>Мы не смогли найти запрашиваемую страницу на Hack Frontend.</p>
      <Link href="/">Вернуться на главную</Link>
    </div>
  )
}

not-found.tsx срабатывает автоматически, когда Next.js не находит роут. Также можно вызвать вручную:

import { notFound } from 'next/navigation'

export default async function DocPage({
  params
}: {
  params: { slug: string }
}) {
  const doc = await getDoc(params.slug)

  if (!doc) {
    notFound()
  }

  return <article>{doc.content}</article>
}

Порядок обработки

layout.tsx
  error.tsx ← перехватывает ошибки из:
    loading.tsx
      not-found.tsx
        page.tsx ← ошибки отсюда поднимаются к error.tsx

Обработка ошибок в Server Actions

Server Actions возвращают ошибки через return, а не throw:

'use server'

export async function updateProfile(formData: FormData) {
  try {
    await db.user.update({ ... })
    revalidatePath('/settings')
    return { success: true }
  } catch (error) {
    return { error: 'Не удалось обновить профиль' }
  }
}

Полезные ресурсы

Связанные темы