getsentry / sentry-javascript

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

@sentry/nextjs not reporting errors from API (serverless) endpoints in Vercel #3917

Closed jmurty closed 2 years ago

jmurty commented 2 years ago

Package + Version

Version:

6.11.0

Description

I was unable to get error reporting from API endpoints deployed in Vercel (as serverless functions) with @sentry/nextjs version 6.11.0 but downgrading to 6.4.1 fixed in.

Our app is a new one built with Next.js 11.1 from create-next-app as of last week.

We used the latest @sentry/nextjs configured according to the documentation, and with additional changes following the with-sentry example: specifically, added _error.js page and err pass through to <Component/> in _app.js.

Before downgrading, client errors were logged fine but I couldn't get error reports from Vercel serverless functions at all. Both client- and server-side errors were logged successfully to Sentry when running the project locally with yarn dev.

This is the failing API endpoint I used to test in file pages/api/boom.js:

import { withSentry } from "@sentry/nextjs";

const handler = async function handler(req, res) {
  // Trigger an exception
  boom();

  res.status(200).send("OK");
};

export default withSentry(handler);

The problem seems similar to other reported issues:

DavidChouinard commented 2 years ago

Bummer, also experiencing this — should have been fixed with #3643 but appears to still be an issue

lobsterkatie commented 2 years ago

Hi, @jmurty and @DavidChouinard. Can you please set debug to true in your server-side Sentry.init() and let me know what you see in your logs? Hopefully that should help in figuring out where things are falling off.

Also, can you please post your sentry.server.config.js and next.config.js?

Thanks!

DavidChouinard commented 2 years ago

Sure, sentry.server.config.js:

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

Sentry.init({
  dsn: process.env.SENTRY_SERVER_DSN,
  environment: process.env.IS_PREVIEW ? 'preview' : process.env.NODE_ENV,
  tracesSampleRate: 1.0,
  debug: true,
});

And Vercel logs for the function invocation:

Sentry Logger [Log]: Integration installed: Http
Sentry Logger [Log]: SDK successfully initialized
Sentry Logger [Log]: Initializing SDK...
Sentry Logger [Log]: SDK already initialized
Sentry Logger [Log]: [Tracing] starting http.server transaction - POST /api/wealth/lead
2021-08-25T01:07:44.624Z    059dc976-2060-4642-a77d-4434c2c070d7    ERROR   Error: Sentry testing - wealth error (backend)
    ... rest of stack trace
2021-08-25T01:07:44.624Z    059dc976-2060-4642-a77d-4434c2c070d7    ERROR   Error: Sentry testing - wealth error (backend)
    ... rest of stack trace
RequestId: 059dc976-2060-4642-a77d-4434c2c070d7 Error: Runtime exited with error: exit status 1
Runtime.ExitError

Note that Sentry works correctly locally but things failed when deployed to Vercel.

jmurty commented 2 years ago

Hi @lobsterkatie I have set up a minimal example Next.js + Sentry project to demonstrate the issue: https://github.com/jmurty/nextjs-sentry-vercel-test

This project is set up using the Next.js and Sentry installation wizards, with some extra steps to work better with Vercel. Hopefully the commit messages explain what I did.

I also set up a new Sentry project to log messages to: https://sentry.io/organizations/murty/issues/?project=5925157 (org murty project nextjs-sentry-vercel-test)

When run the app locally with yarn dev (or with yarn start after yarn build) clicking the button on the index page or visiting the API endpoints /api/test1 through /api/test4 trigger an error that gets logged to the Sentry project.

The same app is deployed to Vercel at https://nextjs-sentry-vercel-test.vercel.app/ But when I trigger the errors on the Vercel site only the client-side (button press) and /api/test4 errors get logged. Errors are not logged for /api/test1, /api/test2, or /api/test3

The /api/test4 API endpoint explicitly catches and captures the error to Sentry.

The /api/test3 is closest to this issue: an error raised in the Next.js handler function that should be caught and captured by withSentry.

The other two examples trigger errors outside the scope of the the handler function and withSentry so should presumably be caught and captured by the custom _error.js page as a fallback. The custom error page is displayed for these endpoints.

Here are the logs from Vercel after hitting the four error-triggering API endpoints: nextjs-sentry-vercel-test.vercel.logs.txt

jmurty commented 2 years ago

I also created a sentry-6.4.1 branch on the example project where I downgraded @sentry/nextjs from 6.11 to 6.4.1: https://github.com/jmurty/nextjs-sentry-vercel-test/tree/sentry-6.4.1

This branch is running on Vercel at https://nextjs-sentry-vercel-test-git-sentry-641-jmurty.vercel.app/ and with it the /api/test3 trigger is logged unlike with version 6.11. This matches my experience where downgrading fixed logging of errors within the handler function.

The client-side and /api/test4 triggers are also logged, like the 6.11 version. The /api/test1 and /api/test2 example errors are not logged.

Here are the Vercel logs again for the 6.4.1 deployment: nextjs-sentry-vercel-test.6_4_1.vercel.logs.txt

lobsterkatie commented 2 years ago

@jmurty @DavidChouinard Thanks to both of you! One of my colleagues has been looking at this while I've been pulled away on another project, and I'm now going to poke at it, too. Will let you know what I come up with!

DavidChouinard commented 2 years ago

@lobsterkatie have you been able to replicate the issue on your side?

Jimmy89 commented 2 years ago

@lobsterkatie I have the same issue, but in my case both on the client and server-side. I use v6.12.0 of sentry, with nextjs v11.1.2 and in my case deployed with @sls-next/serverless-component@3.3.0 with target: "serverless-trace-target" through the option useServerlessTraceTarget: true.

I do not get any error in both client and server logged, unless I enabled capturing console.error statements (with the CaptureConsole of the trace package), which are send to Sentry.

Note: I also tried v6.4.1, but that did not work either.

My sentry config:

import * as Sentry from "@sentry/nextjs";
import { CaptureConsole as CaptureConsoleIntegration } from "@sentry/integrations";
const SENTRY_DSN = process.env.SENTRY_DSN || process.env.NEXT_PUBLIC_SENTRY_DSN;
const ENVIRONMENT = process.env.SENTRY_ENVIRONMENT || process.env.NEXT_PUBLIC_SENTRY_ENVIRONMENT;

Sentry.init({
  dsn: SENTRY_DSN,
  tracesSampleRate: 0.2,
  environment: ENVIRONMENT,
  integrations: [
    new Sentry.Integrations.BrowserTracing({
      tracingOrigins: [API_URL],
      maxTransactionDuration: 60,
    }),
    new CaptureConsoleIntegration({
      levels: ["error"],
    }),
  ],
});

I have the following nextjs config:

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

const ESLintPlugin = require("eslint-webpack-plugin");

const nextjsConfig = {
  poweredByHeader: false,
  webpack: (config, { dev }) => {
    if (dev) {
      config.plugins.push(new ESLintPlugin({
        extensions: ["ts", "tsx", "js", "jsx"],
        failOnError: false,
      }));
    }
    config.externals.push(...[
      {
        mysql: "mysql",
        mysql2: "mysql2",
        pg: "pg",
        mongodb: "mongodb",
        "hdb-pool": "hdb-pool",
        "@sap/hana-client": "@sap/hana-client",
        oracledb: "oracledb",
        "pg-native": "pg-native",
        "pg-query-stream": "pg-query-stream",
        "typeorm-aurora-data-api-driver": "typeorm-aurora-data-api-driver",
        redis: "redis",
        ioredis: "ioredis",
        "better-sqlite3": "better-sqlite3",
        sqlite3: "sqlite3",
        "sql.js": "sql.js",
        mssql: "mssql",
        "react-native-sqlite-storage": "react-native-sqlite-storage",
      },
    ]);
    return config;
  },
};

module.exports = withSentryConfig(
  nextjsConfig,
  {
    dryRun: false,
  },
);
timuric commented 2 years ago

Hi @lobsterkatie I have set up a minimal example Next.js + Sentry project to demonstrate the issue: https://github.com/jmurty/nextjs-sentry-vercel-test

This project is set up using the Next.js and Sentry installation wizards, with some extra steps to work better with Vercel. Hopefully the commit messages explain what I did.

I also set up a new Sentry project to log messages to: https://sentry.io/organizations/murty/issues/?project=5925157 (org murty project nextjs-sentry-vercel-test)

When run the app locally with yarn dev (or with yarn start after yarn build) clicking the button on the index page or visiting the API endpoints /api/test1 through /api/test4 trigger an error that gets logged to the Sentry project.

The same app is deployed to Vercel at https://nextjs-sentry-vercel-test.vercel.app/ But when I trigger the errors on the Vercel site only the client-side (button press) and /api/test4 errors get logged. Errors are not logged for /api/test1, /api/test2, or /api/test3

The /api/test4 API endpoint explicitly catches and captures the error to Sentry.

The /api/test3 is closest to this issue: an error raised in the Next.js handler function that should be caught and captured by withSentry.

The other two examples trigger errors outside the scope of the the handler function and withSentry so should presumably be caught and captured by the custom _error.js page as a fallback. The custom error page is displayed for these endpoints.

Here are the logs from Vercel after hitting the four error-triggering API endpoints: nextjs-sentry-vercel-test.vercel.logs.txt

I have the same issue and I managed to reproduce what @jmurty mentions above.

Using: "@sentry/nextjs": "^6.12.0" "next": "^11.1.2",

anguskeatinge commented 2 years ago

You're a hero @jmurty, I pulled in sentry for a fresh project and banged my head against the wall way too much before downgrading to 6.4.1. Works a charm now.

anguskeatinge commented 2 years ago

Ah shit, so v6.4.1 has a bug where sentry doubles up on the res.send and I get this error:

error - uncaughtException: Error [ERR_STREAM_WRITE_AFTER_END]: write after end
...

So because none of 6.4.1, 6.11 or 6.13 work for me, I've implemented my own withSentry here it is, not perfect but at least it works.

export const withSentry = (handler: ApiHandler) => {
    return async (req: NextApiRequest, res: NextApiResponse) => {
        try {
            const handlerResponse = await handler(req, res);
            return handlerResponse;
        } catch (e) {
            Sentry.init({
                dsn: SENTRY_DSN,
                tracesSampleRate: 0.001,
            });
            Sentry.captureException(e);
            return new Promise<void>((resolve) => {
                Sentry.flush(2000).finally(() => {
                    res.status(500).send('Something went wrong');
                    resolve();
                });
            });
        }
    };
};

Would honestly be so cool if you guys fixed this. Let me know if you want any more info.

DavidChouinard commented 2 years ago

@lobsterkatie any update?

jmurty commented 2 years ago

I have re-tested my example repo after upgrading to @sentry/nextjs version 6.13.2 and the issue remains, specifically the /api/test3 endpoint does not log errors to Sentry from Vercel.

Following @anguskeatinge's suggestion I added a customWithSentry on this branch https://github.com/jmurty/nextjs-sentry-vercel-test/tree/ak-workaround and deployed to Vercel at https://nextjs-sentry-vercel-test-git-ak-workaround-jmurty.vercel.app/

Using the very basic custom withSentry alternative the api/test3 endpoint does log an error to Sentry from Vercel.

jmurty commented 2 years ago

I have taken another look at this in a new branch of my test repo where I copied in the latest official withSentry implementation from @sentry/nextjs then experimented with it for Vercel deployments. I mostly added a bunch of console.log statements to figure out exactly what code was being called from the Vercel function logs.

I ended up with this slight adaptation of the official withSentry that does work for me with the api/test3 endpoint when deployed to Vercel: https://github.com/jmurty/nextjs-sentry-vercel-test/blob/test-official-withsentry/officialWithSentry.ts

What fixed this (in my testing) was to move the clean-up code that finishes a transaction and flushes to Sentry into a stand-alone function, then call that function from both the withSentry handler-wrapping code and the monkeypatched res.end() function.

I found that the res.end() function was not being called, or not called soon enough, when my test project was deployed to Vercel, which meant the Sentry flushing code did not run.

This is a naive fix: I'm not sure why res.end() isn't called as expected for Vercel deployments, or whether there might be a more appropriate target for monkey-patching that is called in both standard Next.js deployments and those in Vercel to avoid the double-calling and the have-I-been-called record-keeping I added. But it works for me, and might work for others as well.

I will submit my version as a PR.

timuric commented 2 years ago

Looks like withSentry is calling synchronous function captureException and throws right afterwards before events are sent to the sentry server. https://github.com/getsentry/sentry-javascript/blob/952850f9845f8fc58f306049063ba6acdae6cfb7/packages/nextjs/src/utils/withSentry.ts#L76-L90

Probably it should be changed to something like this:

catch (e) { 
   if (currentScope) { 
     ...
     captureException(e); 
     await flush(2000)
     throw e; 
   } 
   else {
     throw e; 
   }
 } 

This fix probably explains why the workaround mentioned above is working.

joshsny commented 2 years ago

Also experiencing this issue with @sentry/nextjs v6.13.3

Have experienced issues like this for a long time on NextJS, which makes Sentry almost impossible to use in production, since the issues come and go and take quite a long time to get fixed 😢

martinnabhan commented 2 years ago

Same here! We just stopped using withSentry altogether, and use Sentry.captureException instead. Seems to be working fine.

nickfreeman commented 2 years ago

We're still using Sentry version 6.9.0 which is our last working version that's able to capture serverless errors with withSentry

DavidChouinard commented 2 years ago

@lobsterkatie any word from your colleague?

jmurty commented 2 years ago

Is it likely that the difficulty collecting errors from Vercel will be fixed, and much more reliable, by using the new Middelware feature of the Next.js 12 release?

lobsterkatie commented 2 years ago

Hi, all. Sorry for the delay.

Looks like withSentry is calling synchronous function captureException and throws right afterwards before events are sent to the sentry server.

This is right, and is exactly what https://github.com/getsentry/sentry-javascript/pull/4027 is designed to fix. I (and it) got blocked on a few other things recently, but I'm going to give this another look this week.

Jay-flow commented 1 year ago

Any update? I have the same issue 😭

anguskeatinge commented 1 year ago

I gave up on sentry for my NextJs Vercel setup and just manually pipe all my errors into a database

martinnabhan commented 1 year ago

Not using withSentry but manually capturing exceptions works fine for us on Vercel:

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

const api: NextApiHandler = async (req, res) => {
  try {
    // logic here
  } catch (error) {
    Sentry.captureException(error);
    res.status(500).end();
  }
};
jmurty commented 1 year ago

I’m the original reporter of this issue. It was fixed for me in prior versions of the Sentry NextJS integration, but may have been broken again in more versions – I’m not sure, we mostly run our important apps self-hosted instead of on Vercel.

The new auto-wrap feature seems problematic according to the compatibility matrix in this issue: https://github.com/getsentry/sentry-javascript/issues/6120

maxdeichmann commented 6 months ago

I also have the issue. Does anyone know how to solve this? Here us my sentry configuration for the cloud functions: https://github.com/langfuse/langfuse/blob/main/sentry.server.config.ts

mijiapps commented 5 months ago

Having the same issue.

maxdeichmann commented 5 months ago

@lobsterkatie any update on this?