getsentry / sentry-javascript

Official Sentry SDKs for JavaScript
https://sentry.io
MIT License
7.76k stars 1.52k forks source link

Next.js not capturing client-side errors #10669

Closed LauraImpact closed 4 months ago

LauraImpact commented 4 months ago

Is there an existing issue for this?

How do you use Sentry?

Sentry Saas (sentry.io)

Which SDK are you using?

@sentry/nextjs

SDK Version

7.101.0

Framework Version

"next": "^13.5.4",

Link to Sentry event

No response

SDK Setup

sentry.client.config.ts


import * as Sentry from "@sentry/nextjs";

if (process.env.NODE_ENV !== "development") {
  Sentry.init({
    dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
    environment: process.env.VERCEL_ENV,
    // Adjust this value in production, or use tracesSampler for greater control
    tracesSampleRate: 1,

    // Setting this option to true will print useful information to the console while you're setting up Sentry.
    debug: true,

    replaysOnErrorSampleRate: 1.0,

    // This sets the sample rate to be 10%. You may want this to be 100% while
    // in development and sample at a lower rate in production
    replaysSessionSampleRate: 0.1,

    // You can remove this option if you're not planning to use the Sentry Session Replay feature:
    integrations: [
      Sentry.replayIntegration({
        // Additional Replay configuration goes in here, for example:
        maskAllText: true,
        blockAllMedia: true,
      }),
    ],
  });
}

Steps to Reproduce

When a client-side exception occurs and the error.tsx page is rendered, the error is logged to the console but not captured in Sentry. Server-side issues are captured by Sentry without problems.

src/app/error.tsx

"use client";
import React, { useEffect } from "react";
import * as Sentry from "@sentry/nextjs";
import Image from "next/image";
import Logo from "@/components/assets/Logo";
import useTranslation from "next-translate/useTranslation";

const Error = ({ error }: { error: any }) => {
  const { t } = useTranslation("common");

  useEffect(() => {
    console.log("useEffect error: ", error);
    Sentry.captureException(error);
  }, [error]);

  return (
    <main>
      <div className="relative py-16 px-4 md:bg-gradient-to-b from-white from-133 via-[#222433] via-133.5 to-grey-100 to-133.5 md:pt-32 md:pl-[7%] md:min-h-168 lg:pl-76">
        <Image
          src="/img/background-character.svg"
          alt={t("characterAltText")}
          width="487"
          height="372"
          className="hidden absolute md:block md:py-9 md:left-[60%] lg:left-192 z-0"
          priority={true}
        />
        <div className="flex">
          {" "}
          <div className="max-w-[96%] w-96 mx-auto mt-4 pt-11 px-10 pb-16 border rounded-md bg-white shadow-auth relative z-10 md:mx-0">
            <div className="flex justify-center mb-7">
              <Logo width={840} height={130} />
            </div>
            <h1>{t("unknownError")}</h1>
          </div>
        </div>
      </div>
    </main>
  );
};

export default Error;

Expected Result

When error page is rendered, error should be captured as an issue in Sentry

Actual Result

Logs

Sentry Logger [log]: [Tracing] Finishing navigation transaction: /dashboard/system-admin/users.
Sentry Logger [log]: Adding outcome: "network_error:transaction"
Sentry Logger [error]: Error while sending event: TypeError: Failed to fetch
TypeError: Cannot destructure property 'id' of 'n' as it is null.
useEffect error:  TypeError: Cannot destructure property 'id' of 'n' as it is null.
Sentry Logger [info]: [Replay] Converting buffer to session
Sentry Logger [log]: Sending outcomes: 
[
    {
        "reason": "network_error",
        "category": "transaction",
        "quantity": 1
    }
]
lforst commented 4 months ago

Hi, thanks for writing in! It's awesome that you provided logs!

This line:

Sentry Logger [log]: Sending outcomes: 
[
    {
        "reason": "network_error",
        "category": "transaction",
        "quantity": 1
    }
]

tells us that there was a network error sending the event. In 99.9% of the cases this happens when an adblocker is interfering with requests to Sentry. Can you check whether your browser or any sort of extensions happen to block the reqs?

LauraImpact commented 4 months ago

Thanks for the response. I've tried adding the tunnel route to my next.config, trying a different browser (switched from Chrome to Safari) and I don't have any ad-blockers but the issue is still persisting.

 sentry: {
    tunnelRoute: "/monitoring-tunnel",
  },
lforst commented 4 months ago

I am not aware of any issues like this in the SDK. Would you mind sharing a small reproduction example that lets us reproduce this behaviour? As an intermediary step, please check that your DSN env var is set and correct. Thanks!

LauraImpact commented 4 months ago

I can't really show a reproduction at the moment. The error page is unchanged from the example I showed above. I think the DSN env var is correct because I have no issues with capturing the server-side errors. These are the logs when I trigger a client-side error now I have:

 sentry: {
    tunnelRoute: "/monitoring-tunnel",
  },

enabled. I'm still getting the network_error message.

 Sentry Logger [log]: [Tracing] Finishing navigation transaction: /dashboard/system-admin/users.
 TypeError: Cannot destructure property 'id' of 'n' as it is null.
 Client-side error:  TypeError: Cannot destructure property 'id' of 'n' as it is null.
 Sentry Logger [info]: [Replay] Converting buffer to session
 Sentry Logger [log]: Sending outcomes: 
   [
    {
        "reason": "network_error",
        "category": "transaction",
        "quantity": 1
    }
]

This is my next.config.js:

const webpack = require("webpack");
const nextTranslate = require("next-translate-plugin");

/** @type {import('next').NextConfig} */
const nextConfig = nextTranslate({
  webpack: (config, { isServer }) => {
    if (!isServer) {
      config.resolve.fallback.fs = false;

      /** do not allow the admin firebase to be permitted on the client */
      config.plugins.push(
        new webpack.IgnorePlugin({
          resourceRegExp: /admin\.firebase/,
        })
      );
    }
    return config;
  },
  sentry: {
    /** Set up tunneling to by pass browser ad-blockers https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/#configure-tunneling-to-avoid-ad-blockers */
    tunnelRoute: "/monitoring-tunnel",
  },
  // It's supported by default, the option is not needed
  // experimental: { appDir: true },
});

module.exports = nextConfig;

// Injected content via Sentry wizard below

const { withSentryConfig } = require("@sentry/nextjs");

module.exports = withSentryConfig(
  module.exports,
  {
    // For all available options, see:
    // https://github.com/getsentry/sentry-webpack-plugin#options

    // Suppresses source map uploading logs during build
    silent: true,
    org: "climatezero",
    project: "climate-zero",
  },
  {
    // For all available options, see:
    // https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/

    // Upload a larger set of source maps for prettier stack traces (increases build time)
    widenClientFileUpload: true,

    // Transpiles SDK to be compatible with IE11 (increases bundle size)
    transpileClientSDK: true,

    // Routes browser requests to Sentry through a Next.js rewrite to circumvent ad-blockers (increases server load)
    tunnelRoute: "/monitoring",

    // Hides source maps from generated client bundles
    hideSourceMaps: true,

    // Automatically tree-shake Sentry logger statements to reduce bundle size
    disableLogger: false,

    // Enables automatic instrumentation of Vercel Cron Monitors.
    // See the following for more information:
    // https://docs.sentry.io/product/crons/
    // https://vercel.com/docs/cron-jobs
    automaticVercelMonitors: true,
  }
);

and my sentry.client.config.ts:

// This file configures the initialization of Sentry on the client.
// The config you add here will be used whenever a users loads a page in their browser.
// https://docs.sentry.io/platforms/javascript/guides/nextjs/

import * as Sentry from "@sentry/nextjs";

if (process.env.NODE_ENV !== "development") {
  Sentry.init({
    dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
    environment: process.env.VERCEL_ENV,
    // Adjust this value in production, or use tracesSampler for greater control
    tracesSampleRate: 1,

    // Setting this option to true will print useful information to the console while you're setting up Sentry.
    debug: true,

    replaysOnErrorSampleRate: 1.0,

    // This sets the sample rate to be 10%. You may want this to be 100% while
    // in development and sample at a lower rate in production
    replaysSessionSampleRate: 0.1,

    // You can remove this option if you're not planning to use the Sentry Session Replay feature:
    integrations: [
      Sentry.replayIntegration({
        // Additional Replay configuration goes in here, for example:
        maskAllText: true,
        blockAllMedia: true,
      }),
    ],
  });
}

Thank you for your help, I appreciate it.

lforst commented 4 months ago

Please check you followed the setup here to set up react rendering errors: https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/#report-react-component-render-errors

Since otherwise your setup is pretty much what we tell you to do in the docs and I cannot reproduce the issue you're describing we certainly need a way to reproduce this. When you have the time please try to set up a very basic Next.js app with this behaviour and share it with us. Thank you!

arnaudjnn commented 4 months ago

@LauraImpact

I had the same issue. The problem was due to my middleware config and tunnelRoute routing to /monitoring

I fixed it by adding monitoring route as an exception

 // BEFORE
export const config = {
  // Skip all paths that aren't pages that you'd like to internationalize
  matcher: ["/((?!api|_next|.*\\..*).*)"],
};

// AFTER
export const config = {
  // Skip all paths that aren't pages that you'd like to internationalize
  matcher: ["/((?!api|_next|monitoring|.*\\..*).*)"],
};
lforst commented 4 months ago

@arnaudjnn Ah thanks for that! I wrote down a task for myself to mention this in the docs and in the wizard setup.

LauraImpact commented 4 months ago

Ah I think that could be it! Thanks @arnaudjnn!

LauraImpact commented 4 months ago

That has resolved the issue. Thank you both for your help

lforst commented 4 months ago

Opened https://github.com/getsentry/sentry-wizard/pull/544 and https://github.com/getsentry/sentry-docs/pull/9306 to better document this interaction.

kunzeleric commented 2 months ago

I'm getting this error even though I applied that solution :( Every request on the deploy hits 404.. My website is deployed on netlify! Any clues why this keeps happening?

lforst commented 1 month ago

@kunzeleric Please see https://github.com/getsentry/sentry-javascript/issues/8869#issuecomment-1695355649

kunzeleric commented 1 month ago

@lforst thanks a lot! :)