Capturing Server Component and Server Action errors

In production, Next.js replaces a Server Component error with an opaque digest string. The original message and stack never reach the browser by design — you have to capture them on the server.

Why your error boundary shows nothing useful

When a Server Component throws in production, Next.js sends the client a digest — a hash — instead of the message and stack. That is a deliberate security decision: server-side error text routinely contains connection strings, file paths and internal hostnames.

The consequence is that a client-side `error.tsx` boundary cannot report anything diagnostic. It receives the digest and nothing else. Reporting has to happen server-side, where the real error still exists.

Use instrumentation.ts and onRequestError

Next.js loads `instrumentation.ts` from your project root once per server process, before the rest of the application. That is the correct place to initialise any monitoring SDK, because it runs before the code that might throw.

The same file can export `onRequestError`, which Next.js calls for server-side errors — including Server Components and Server Actions — with the real error plus a context object identifying the route and whether it was a render or an action.

instrumentation.ts
import { VantaTrace } from '@vantatrace/sdk';

const vantaTrace = new VantaTrace({
  apiKey: process.env.VANTATRACE_API_KEY,
});

export async function register() {
  vantaTrace.initGlobalHandlers();
}

// Called by Next.js for server-side errors, with the UNDIGESTED error.
export async function onRequestError(
  error: unknown,
  request: { path: string; method: string; headers: Record<string, string | undefined> },
  context: { routerKind: string; routePath: string; routeType: string }
) {
  vantaTrace.captureException(error, {
    route: context.routePath,
    method: request.method,
    metadata: {
      routerKind: context.routerKind,  // 'App Router' | 'Pages Router'
      routeType: context.routeType,    // 'render' | 'route' | 'action' | 'middleware'
      path: request.path,
    },
  });
}

Correlating a user report with a server error

The digest is not useless — it is the join key. Log it in your `error.tsx` boundary and include it in your report metadata, and a user who says "I saw an error page" can be matched to the exact server-side exception.

Without that correlation you are left guessing which of the day's errors the user actually hit.

app/error.tsx
'use client';

export default function Error({ error }: { error: Error & { digest?: string } }) {
  return (
    <div role="alert">
      <h2>Something went wrong</h2>
      {/* Surfacing the digest lets support match this to the server-side error. */}
      {error.digest && <p>Reference: {error.digest}</p>}
    </div>
  );
}

What this does not cover

Errors thrown in Client Components never reach the server, so `onRequestError` will not see them. Those need a browser-side reporter, which the Node.js SDK does not provide.

Errors inside a `try/catch` that you handle are also not reported — correctly so. If you want those recorded, call `captureException` in the catch block explicitly.

Related guides