Q: How to make a custom _error page with Sentry to catch all 404 and other errors?
Versions:
- Next.js v13.1
- Node v16.16.0
- Typescript Version 4.7.3
The custom _error page does not catch any errors.
I have followed this guide from Sentry for Next.js: https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/#create-a-custom-_error-page
My _error.tsx page:
/**
* NOTE: This requires `@sentry/nextjs` version 7.3.0 or higher.
*
* This page is loaded by Nextjs:
* - on the server, when data-fetching methods throw or reject
* - on the client, when `getInitialProps` throws or rejects
* - on the client, when a React lifecycle method throws or rejects, and it's
* caught by the built-in Nextjs error boundary
*
* See:
* - https://nextjs.org/docs/basic-features/data-fetching/overview
* - https://nextjs.org/docs/api-reference/data-fetching/get-initial-props
* - https://reactjs.org/docs/error-boundaries.html
*/
import * as Sentry from '@sentry/nextjs';
import type { NextPage } from 'next';
import type { ErrorProps } from 'next/error';
import NextErrorComponent from 'next/error';
const CustomErrorComponent: NextPage<ErrorProps> = (props) => {
// If you're using a Nextjs version prior to 12.2.1, uncomment this to
// compensate for https://github.com/vercel/next.js/issues/8592
// Sentry.captureUnderscoreErrorException(props);
return <NextErrorComponent statusCode={props.statusCode} />;
};
CustomErrorComponent.getInitialProps = async (contextData) => {
// In case this is running in a serverless function, await this in order to give Sentry
// time to send the error before the lambda exits
await Sentry.captureUnderscoreErrorException(contextData);
console.log('getInitialProps in _error.tsx')
// This will contain the status code of the response
return NextErrorComponent.getInitialProps(contextData);
};
export default CustomErrorComponent;
My next.config.js
file:
const { withSentryConfig } = require('@sentry/nextjs');
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
env: {
ENV_FLAVOR: process.env.ENV_FLAVOR,
},
sentry: {
// Use `hidden-source-map` rather than `source-map` as the Webpack `devtool`
// for client-side builds. (This will be the default starting in
// `@sentry/nextjs` version 8.0.0.) See
// https://webpack.js.org/configuration/devtool/ and
// https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/#use-hidden-source-map
// for more information.
hideSourceMaps: true,
},
// Use the CDN in production and localhost for development.
assetPrefix: '[redacted]',
eslint: {
dirs: ['pages', 'components', 'utils', 'hooks', 'server'],
},
images: {
domains: [
'[redacted]',
],
},
output: 'standalone',
// https://www.npmjs.com/package/@svgr/webpack
// SVGR - enables to write .svg files as components with className, etc. - <Icon className='' {...props} />
webpack(config) {
config.module.rules.push({
test: /\.svg$/i,
issuer: /\.(ts|tsx|js|jsx)$/,
use: [
{
loader: '@svgr/webpack',
options: {
typescript: true,
icon: true,
},
},
],
});
return config;
},
};
const sentryWebpackPluginOptions = {
enabled: true,
// Additional config options for the Sentry Webpack plugin. Keep in mind that
// the following options are set automatically, and overriding them is not
// recommended:
// release, url, org, project, authToken, configFile, stripPrefix,
// urlPrefix, include, ignore
org: '[redacted]',
project: '[redacted]',
url: 'https://sentry.[redacted]',
authToken: process.env.SENTRY_AUTH_TOKEN,
debug: true,
silent: false, // Suppresses all logs
// For all available options, see:
// https://github.com/getsentry/sentry-webpack-plugin#options.
};
module.exports = withSentryConfig(nextConfig, sentryWebpackPluginOptions)
My sentry.client.config.js
file:
// This file configures the initialization of Sentry on the browser.
// The config you add here will be used whenever a page is visited.
// https://docs.sentry.io/platforms/javascript/guides/nextjs/
import * as Sentry from '@sentry/nextjs';
const SENTRY_DSN = process.env.SENTRY_DSN || process.env.NEXT_PUBLIC_SENTRY_DSN;
Sentry.init({
enabled: true,
dsn: SENTRY_DSN || 'https://[redacted]@sentry.[redacted]/[redacted]',
environment: process.env.ENV_FLAVOR || process.env.NODE_ENV,
// Adjust this value in production, or use tracesSampler for greater control
tracesSampleRate: 1.0,
debug: true,
silent: false, // Suppresses all logs
// ...
// Note: if you want to override the automatic release value, do not set a
// `release` value here - use the environment variable `SENTRY_RELEASE`, so
// that it will also get attached to your source maps
});
My sentry.server.config.js
file:
// This file configures the initialization of Sentry on the server.
// The config you add here will be used whenever the server handles a request.
// https://docs.sentry.io/platforms/javascript/guides/nextjs/
import * as Sentry from '@sentry/nextjs';
const SENTRY_DSN = process.env.SENTRY_DSN || process.env.NEXT_PUBLIC_SENTRY_DSN;
Sentry.init({
enabled: true,
dsn: SENTRY_DSN || 'https://[redacted]@sentry.[redacted]/[redacted]',
// Adjust this value in production, or use tracesSampler for greater control
tracesSampleRate: 1.0,
debug: true
silent: false, // Suppresses all logs
// ...
// Note: if you want to override the automatic release value, do not set a
// `release` value here - use the environment variable `SENTRY_RELEASE`, so
// that it will also get attached to your source maps
});
Run yarn dev
log:
[07:09:41] Starting compilation in watch mode...
ready - started server on 0.0.0.0:3000, url: http://localhost:3000
info - Loaded env from /[redacted]/.env
[Sentry Webpack Plugin] DRY Run Mode
[Sentry Webpack Plugin] DRY Run Mode
[Sentry Webpack Plugin] DRY Run Mode
[Sentry Webpack Plugin] DEBUG: Injecting release code
[Sentry Webpack Plugin] DEBUG: Loaders:
[
'<unknown loader>',
'<unknown loader>',
'<unknown loader>',
'<unknown loader>',
'next-image-loader',
'<unknown loader>',
'@svgr/webpack',
'/[redacted]/node_modules/@sentry/nextjs/cjs/config/loaders/valueInjectionLoader.js',
'/[redacted]/node_modules/@sentry/nextjs/cjs/config/loaders/valueInjectionLoader.js',
'/[redacted]/node_modules/@sentry/webpack-plugin/src/sentry.loader.js'
]
[Sentry Webpack Plugin] DEBUG: Added loaders:
[
'/[redacted]/node_modules/@sentry/webpack-plugin/src/sentry.loader.js'
]
[Sentry Webpack Plugin] DEBUG: Removed loaders:
[]
[Sentry Webpack Plugin] DEBUG: Entry:
[Sentry Webpack Plugin] DEBUG: Added entry:
[]
[Sentry Webpack Plugin] DEBUG: Removed entry:
[]
[Sentry Webpack Plugin] DEBUG: Injecting release code
[Sentry Webpack Plugin] DEBUG: Loaders:
[
'<unknown loader>',
'<unknown loader>',
'<unknown loader>',
'<unknown loader>',
'next-image-loader',
'@svgr/webpack',
'/[redacted]/node_modules/@sentry/nextjs/cjs/config/loaders/valueInjectionLoader.js',
'/[redacted]/node_modules/@sentry/nextjs/cjs/config/loaders/valueInjectionLoader.js',
'/[redacted]/node_modules/@sentry/nextjs/cjs/config/loaders/proxyLoader.js',
'/[redacted]/node_modules/@sentry/webpack-plugin/src/sentry.loader.js'
]
[Sentry Webpack Plugin] DEBUG: Added loaders:
[
'/[redacted]/node_modules/@sentry/webpack-plugin/src/sentry.loader.js'
]
[Sentry Webpack Plugin] DEBUG: Removed loaders:
[]
[Sentry Webpack Plugin] DEBUG: Entry:
[Sentry Webpack Plugin] DEBUG: Added entry:
[]
[Sentry Webpack Plugin] DEBUG: Removed entry:
[]
[Sentry Webpack Plugin] DEBUG: Injecting release code
[Sentry Webpack Plugin] DEBUG: Loaders:
[
'<unknown loader>',
'next-middleware-asset-loader',
'next-middleware-wasm-loader',
'<unknown loader>',
'<unknown loader>',
'<unknown loader>',
'<unknown loader>',
'next-image-loader',
'<unknown loader>',
'@svgr/webpack',
'/[redacted]/node_modules/@sentry/nextjs/cjs/config/loaders/valueInjectionLoader.js',
'/[redacted]/node_modules/@sentry/nextjs/cjs/config/loaders/valueInjectionLoader.js',
'/[redacted]/node_modules/@sentry/nextjs/cjs/config/loaders/proxyLoader.js',
'/[redacted]/node_modules/@sentry/webpack-plugin/src/sentry.loader.js'
]
[Sentry Webpack Plugin] DEBUG: Added loaders:
[
'/[redacted]/node_modules/@sentry/webpack-plugin/src/sentry.loader.js'
]
[Sentry Webpack Plugin] DEBUG: Removed loaders:
[]
[Sentry Webpack Plugin] DEBUG: Entry:
[Sentry Webpack Plugin] DEBUG: Added entry:
[]
[Sentry Webpack Plugin] DEBUG: Removed entry:
[]
[Sentry Webpack Plugin] Creating new release:
'development'
[Sentry Webpack Plugin] Calling upload-sourcemaps with:
{
finalize: true,
rewrite: true,
include: [
{
paths: [
'/[redacted]/.next/static/chunks/pages'
],
urlPrefix: '~/_next/static/chunks/pages'
}
],
ignore: [],
configFile: 'sentry.properties',
stripPrefix: [ 'webpack://_N_E/' ],
urlPrefix: '~/_next',
entries: [Function: entries],
release: 'development',
dryRun: true,
enabled: true,
org: '[redacted]',
project: '[redacted]',
url: 'https://sentry./[redacted]',
environment: 'development',
authToken: '[redacted]',
debug: true,
silent: false
}
[Sentry Webpack Plugin] Finalizing release:
'development'
[Sentry Webpack Plugin] Creating new release:
'development'
[Sentry Webpack Plugin] Calling upload-sourcemaps with:
{
finalize: true,
rewrite: true,
include: [
{
paths: [
'/[redacted]/.next/server/pages/'
],
urlPrefix: '~/_next/server/pages'
},
{
paths: [
'/[redacted]/.next/server/chunks/'
],
urlPrefix: '~/_next/server/chunks'
}
],
ignore: [],
configFile: 'sentry.properties',
stripPrefix: [ 'webpack://_N_E/' ],
urlPrefix: '~/_next',
entries: [Function: entries],
release: 'development',
dryRun: true,
enabled: true,
org: '[redacted]',
project: '[redacted]',
url: 'https://sentry./[redacted]',
environment: 'development',
authToken: '[redacted]',
debug: true,
silent: false
}
[Sentry Webpack Plugin] Finalizing release:
'development'
[Sentry Webpack Plugin] Creating new release:
'development'
[Sentry Webpack Plugin] Calling upload-sourcemaps with:
{
finalize: true,
rewrite: true,
include: [
{
paths: [
'/[redacted]/.next/server/pages/'
],
urlPrefix: '~/_next/server/pages'
},
{
paths: [
'/[redacted]/.next/server/chunks/'
],
urlPrefix: '~/_next/server/chunks'
}
],
ignore: [],
configFile: 'sentry.properties',
stripPrefix: [ 'webpack://_N_E/' ],
urlPrefix: '~/_next',
entries: [Function: entries],
release: 'development',
dryRun: true,
enabled: true,
org: '[redacted]',
project: '[redacted]',
url: 'https://sentry./[redacted]',
environment: 'development',
authToken: '[redacted]',
debug: true,
silent: false
}
[Sentry Webpack Plugin] Finalizing release:
'development'
event - compiled client and server successfully in 3.6s (689 modules)
[07:09:47] Found 0 errors. Watching for file changes.
wait - compiling /middleware (client and server)...
[Sentry Webpack Plugin] Creating new release:
'development'
[Sentry Webpack Plugin] Calling upload-sourcemaps with:
{
finalize: true,
rewrite: true,
include: [
{
paths: [
'/[redacted]/.next/server/pages/'
],
urlPrefix: '~/_next/server/pages'
},
{
paths: [
'/[redacted]/.next/server/chunks/'
],
urlPrefix: '~/_next/server/chunks'
}
],
ignore: [],
configFile: 'sentry.properties',
stripPrefix: [ 'webpack://_N_E/' ],
urlPrefix: '~/_next',
entries: [Function: entries],
release: 'development',
dryRun: true,
enabled: true,
org: '[redacted]',
project: '[redacted]',
url: 'https://sentry./[redacted]',
environment: 'development',
authToken: '[redacted]',
debug: true,
silent: false
}
[Sentry Webpack Plugin] Finalizing release:
'development'
event - compiled successfully in 161 ms (41 modules)
wait - compiling /_error (client and server)...
[Sentry Webpack Plugin] Creating new release:
'development'
[Sentry Webpack Plugin] Calling upload-sourcemaps with:
{
finalize: true,
rewrite: true,
include: [
{
paths: [
'/[redacted]/.next/static/chunks/pages'
],
urlPrefix: '~/_next/static/chunks/pages'
}
],
ignore: [],
configFile: 'sentry.properties',
stripPrefix: [ 'webpack://_N_E/' ],
urlPrefix: '~/_next',
entries: [Function: entries],
release: 'development',
dryRun: true,
enabled: true,
org: '[redacted]',
project: '[redacted]',
url: 'https://sentry./[redacted]',
environment: 'development',
authToken: '[redacted]',
debug: true,
silent: false
}
[Sentry Webpack Plugin] Finalizing release:
'development'
[Sentry Webpack Plugin] Creating new release:
'development'
[Sentry Webpack Plugin] Calling upload-sourcemaps with:
{
finalize: true,
rewrite: true,
include: [
{
paths: [
'/[redacted]/.next/server/pages/'
],
urlPrefix: '~/_next/server/pages'
},
{
paths: [
'/[redacted]/.next/server/chunks/'
],
urlPrefix: '~/_next/server/chunks'
}
],
ignore: [],
configFile: 'sentry.properties',
stripPrefix: [ 'webpack://_N_E/' ],
urlPrefix: '~/_next',
entries: [Function: entries],
release: 'development',
dryRun: true,
enabled: true,
org: '[redacted]',
project: '[redacted]',
url: 'https://sentry./[redacted]',
environment: 'development',
authToken: '[redacted]',
debug: true,
silent: false
}
[Sentry Webpack Plugin] Finalizing release:
'development'
event - compiled client and server successfully in 501 ms (689 modules)
Sentry Logger [log]: Initializing SDK...
Sentry Logger [log]: Integration installed: InboundFilters
Sentry Logger [log]: Integration installed: FunctionToString
Sentry Logger [log]: Integration installed: Console
Sentry Logger [log]: Integration installed: Http
Sentry Logger [log]: Integration installed: OnUncaughtException
Sentry Logger [log]: Integration installed: OnUnhandledRejection
Sentry Logger [log]: Integration installed: ContextLines
Sentry Logger [log]: Integration installed: Context
Sentry Logger [log]: Integration installed: Modules
Sentry Logger [log]: Integration installed: RequestData
Sentry Logger [log]: Integration installed: LinkedErrors
Sentry Logger [log]: Integration installed: Postgres
Sentry Logger [log]: Integration installed: RewriteFrames
Sentry Logger [log]: SDK successfully initialized
warn - You have added a custom /_error page without a custom /404 page. This prevents the 404 page from being auto statically optimized.
See here for info: https://nextjs.org/docs/messages/custom-error-no-custom-404
Sentry Logger [log]: [Tracing] starting http.server transaction - /_error
Sentry Logger [log]: [Tracing] Starting 'function.nextjs' span on transaction '/_error' (aa456f6d383caa73).
getInitialProps in _error.tsx
Sentry Logger [log]: [Tracing] Finishing 'function.nextjs' span on transaction '/_error' (aa456f6d383caa73).
Sentry Logger [log]: [Tracing] Finishing http.server transaction: /_error.
Sentry Logger [log]: Flushing events...
Sentry Logger [log]: Done flushing events
Sentry Logger [log]: [Tracing] Continuing trace 7a3dfcb765b743ac893c35809336ad1b.
Sentry Logger [log]: [Tracing] starting http.server transaction - GET /api/auth/session
Sentry Logger [log]: [Tracing] Continuing trace 7a3dfcb765b743ac893c35809336ad1b.
Sentry Logger [log]: [Tracing] starting http.server transaction - GET /api/auth/session
wait - compiling /api/auth/[...nextauth] (client and server)...
[Sentry Webpack Plugin] Creating new release:
'development'
[Sentry Webpack Plugin] Calling upload-sourcemaps with:
{
finalize: true,
rewrite: true,
include: [
{
paths: [
'/[redacted]/.next/server/pages/'
],
urlPrefix: '~/_next/server/pages'
},
{
paths: [
'/[redacted]/.next/server/chunks/'
],
urlPrefix: '~/_next/server/chunks'
}
],
ignore: [],
configFile: 'sentry.properties',
stripPrefix: [ 'webpack://_N_E/' ],
urlPrefix: '~/_next',
entries: [Function: entries],
release: 'development',
dryRun: true,
enabled: true,
org: '[redacted]',
project: '[redacted]',
url: 'https://sentry./[redacted]',
environment: 'development',
authToken: '[redacted]',
debug: true,
silent: false
}
[Sentry Webpack Plugin] Finalizing release:
'development'
event - compiled successfully in 186 ms (156 modules)
[Sentry Webpack Plugin] Creating new release:
'development'
[Sentry Webpack Plugin] Calling upload-sourcemaps with:
{
finalize: true,
rewrite: true,
include: [
{
paths: [
'/[redacted]/.next/server/pages/'
],
urlPrefix: '~/_next/server/pages'
},
{
paths: [
'/[redacted]/.next/server/chunks/'
],
urlPrefix: '~/_next/server/chunks'
}
],
ignore: [],
configFile: 'sentry.properties',
stripPrefix: [ 'webpack://_N_E/' ],
urlPrefix: '~/_next',
entries: [Function: entries],
release: 'development',
dryRun: true,
enabled: true,
org: '[redacted]',
project: '[redacted]',
url: 'https://sentry./[redacted]',
environment: 'development',
authToken: '[redacted]',
debug: true,
silent: false
}
[Sentry Webpack Plugin] Finalizing release:
'development'
Sentry Logger [log]: [Tracing] Continuing trace 7a3dfcb765b743ac893c35809336ad1b.
Sentry Logger [log]: [Tracing] starting http.server transaction - GET /api/auth/[...nextauth]
Sentry Logger [log]: [Tracing] Continuing trace 7a3dfcb765b743ac893c35809336ad1b.
Sentry Logger [log]: [Tracing] starting http.server transaction - GET /api/auth/[...nextauth]
query: SELECT * FROM current_schema()
Sentry Logger [log]: [Tracing] Starting 'db' span on transaction 'GET /api/auth/[...nextauth]' (ab9317efe6069f6b).
Sentry Logger [log]: [Tracing] Finishing 'db' span on transaction 'GET /api/auth/[...nextauth]' (ab9317efe6069f6b).
query: SHOW server_version;
Sentry Logger [log]: [Tracing] Starting 'db' span on transaction 'GET /api/auth/[...nextauth]' (ab9317efe6069f6b).
Sentry Logger [log]: [Tracing] Finishing 'db' span on transaction 'GET /api/auth/[...nextauth]' (ab9317efe6069f6b).
query: SELECT "user"."id" AS "user_id", "user"."name" AS "user_name", "user"."email" AS "user_email", "user"."profile_picture" AS "user_profile_picture", "user"."created_at" AS "user_created_at", "user"."updated_at" AS "user_updated_at", "user"."bio" AS "user_bio", "user"."job_title" AS "user_job_title", "user"."linkedin_url" AS "user_linkedin_url", "user"."twitter_url" AS "user_twitter_url", "user"."website" AS "user_website", "user"."company_name" AS "user_company_name", "user"."company_size" AS "user_company_size", "socials"."id" AS "socials_id", "socials"."name" AS "socials_name", "socials"."nickname" AS "socials_nickname", "socials"."profile_picture" AS "socials_profile_picture", "socials"."email" AS "socials_email", "socials"."provider" AS "socials_provider", "socials"."userId" AS "socials_userId", "votes"."id" AS "votes_id", "votes"."vote_type" AS "votes_vote_type", "votes"."session_id" AS "votes_session_id", "votes"."created_at" AS "votes_created_at", "votes"."updated_at" AS "votes_updated_at", "votes"."user_id" AS "votes_user_id", "votes"."article_id" AS "votes_article_id" FROM "users" "user" LEFT JOIN "social_accounts" "socials" ON "socials"."userId"="user"."id" LEFT JOIN "article_votes" "votes" ON "votes"."user_id"="user"."id" WHERE "user"."email" = $1 -- PARAMETERS: ["[redacted]"]
Sentry Logger [log]: [Tracing] Starting 'db' span on transaction 'GET /api/auth/[...nextauth]' (a471a31253c2516e).
Sentry Logger [log]: [Tracing] Finishing 'db' span on transaction 'GET /api/auth/[...nextauth]' (a471a31253c2516e).
query: SELECT "user"."id" AS "user_id", "user"."name" AS "user_name", "user"."email" AS "user_email", "user"."profile_picture" AS "user_profile_picture", "user"."created_at" AS "user_created_at", "user"."updated_at" AS "user_updated_at", "user"."bio" AS "user_bio", "user"."job_title" AS "user_job_title", "user"."linkedin_url" AS "user_linkedin_url", "user"."twitter_url" AS "user_twitter_url", "user"."website" AS "user_website", "user"."company_name" AS "user_company_name", "user"."company_size" AS "user_company_size", "socials"."id" AS "socials_id", "socials"."name" AS "socials_name", "socials"."nickname" AS "socials_nickname", "socials"."profile_picture" AS "socials_profile_picture", "socials"."email" AS "socials_email", "socials"."provider" AS "socials_provider", "socials"."userId" AS "socials_userId", "votes"."id" AS "votes_id", "votes"."vote_type" AS "votes_vote_type", "votes"."session_id" AS "votes_session_id", "votes"."created_at" AS "votes_created_at", "votes"."updated_at" AS "votes_updated_at", "votes"."user_id" AS "votes_user_id", "votes"."article_id" AS "votes_article_id" FROM "users" "user" LEFT JOIN "social_accounts" "socials" ON "socials"."userId"="user"."id" LEFT JOIN "article_votes" "votes" ON "votes"."user_id"="user"."id" WHERE "user"."email" = $1 -- PARAMETERS: ["[redacted]"]
Sentry Logger [log]: [Tracing] Starting 'db' span on transaction 'GET /api/auth/[...nextauth]' (ab9317efe6069f6b).
Sentry Logger [log]: [Tracing] Finishing http.server transaction: GET /api/auth/[...nextauth].
Sentry Logger [log]: Flushing events...
Sentry Logger [log]: [Tracing] Finishing 'db' span on transaction 'GET /api/auth/[...nextauth]' (ab9317efe6069f6b).
Sentry Logger [log]: [Tracing] Finishing http.server transaction: GET /api/auth/[...nextauth].
Sentry Logger [log]: Flushing events...
Sentry Logger [log]: Done flushing events
Sentry Logger [log]: Done flushing events
Sentry Logger [log]: [Tracing] Continuing trace 7a3dfcb765b743ac893c35809336ad1b.
Sentry Logger [log]: [Tracing] starting http.server transaction - /some-non-existing-page
Sentry Logger [log]: Initializing SDK...
Sentry Logger [log]: SDK already initialized
Sentry Logger [log]: [Tracing] starting http.server transaction - /_error
Sentry Logger [log]: [Tracing] Starting 'function.nextjs' span on transaction '/_error' (a3bef10759093a80).
getInitialProps in _error.tsx
Sentry Logger [log]: [Tracing] Finishing 'function.nextjs' span on transaction '/_error' (a3bef10759093a80).
Sentry Logger [log]: [Tracing] Finishing http.server transaction: /_error.
Sentry Logger [log]: Flushing events...
Sentry Logger [log]: Done flushing events
Sentry Logger [log]: [Tracing] Finishing http.server transaction: /_error.
A workaround I don't want to use:
Just a note here that I don't want to use return { notFound: true }
(ref: https://nextjs.org/docs/api-reference/data-fetching/get-static-props#notfound) in all pages because it logs a weird error in Sentry that doesn't say anything.