sentry-javascript icon indicating copy to clipboard operation
sentry-javascript copied to clipboard

On SSR client._captureRequestSession is not a function

Open Dima-Dim opened this issue 1 year ago • 8 comments

Is there an existing issue for this?

  • [X] I have checked for existing issues https://github.com/getsentry/sentry-javascript/issues
  • [X] I have reviewed the documentation https://docs.sentry.io/
  • [X] I am using the latest SDK release https://github.com/getsentry/sentry-javascript/releases

How do you use Sentry?

Self-hosted/on-premise

Which SDK are you using?

@sentry/react

SDK Version

8.8.0

Framework Version

React 18.3.1

Link to Sentry event

No response

SDK Setup

const config = {
    dsn,
    environment: nodeEnv,
    release: appReleaseName,
    ignoreErrors: ['Failed to fetch', 'Connection disconnected', 'Network request failed', 'NetworkError', 'withrealtime/messaging'],
    replaysSessionSampleRate: Number(process.env.SENTRY_REPLAYS_SESSION_SAMPLE_RATE) || 0.1,
    replaysOnErrorSampleRate: Number(process.env.SENTRY_REPLAYS_ON_ERROR_SAMPLE_RATE) || 0.1,
    integrations: [
      Sentry.browserTracingIntegration(),
      Sentry.breadcrumbsIntegration({
        console: true,
        dom: true,
        fetch: true,
        history: true,
        xhr: true,
      }),
      Sentry.globalHandlersIntegration({
        onerror: true,
        onunhandledrejection: true,
      }),
      Sentry.captureConsoleIntegration({
        levels: ['error'],
      }),
      Sentry.replayIntegration({
        maskAllText: false,
        maskAllInputs: false,
        blockAllMedia: false,
        mask: ['[type="password"]'],
      }),
    ],
    sampleRate: Number(process.env.SENTRY_CLIENT_SAMPLE_RATE) || 0.1,
    tracesSampleRate: Number(process.env.SENTRY_CLIENT_TRACES_SAMPLE_RATE) || 0.1,
    normalizeDepth: 5,
  };

Steps to Reproduce

Standard installation and use with SSR.

Expected Result

No errors

Actual Result

On SSR Uncaught Exception: TypeError: client._captureRequestSession is not a function after update to version 8.

Uncaught Exception: TypeError: client._captureRequestSession is not a function

{
  arguments: [
    Uncaught Exception:,
    {
      message: client._captureRequestSession is not a function,
      name: TypeError,
      stack: TypeError: client._captureRequestSession is not a function
          at Immediate.<anonymous> (/xxx/node_modules/@sentry/node/cjs/integrations/http.js:109:45)
          at process.processImmediate (node:internal/timers:478:21)
          at process.callbackTrampoline (node:internal/async_hooks:130:17)
    }
  ],
  logger: console
}

Dima-Dim avatar Jun 11 '24 11:06 Dima-Dim

Hi @Dima-Dim thanks for writing in!

_captureRequestSession is only available in server-side SDKs based on the ServerRuntimeClient. So the most prominent example would be @sentry/node or any SDK inheriting from @sentry/node. According to the issue, you're using @sentry/react which uses BrowserClient and hence doesn't expose this method. ~Are you using a server Sentry SDK in addition?~ The stack trace tells me, you're also using @sentry/node. Would you mind sharing a bit more about your SSR setup?

Lms24 avatar Jun 11 '24 11:06 Lms24

Hi @Dima-Dim thanks for writing in!

_captureRequestSession is only available in server-side SDKs based on the ServerRuntimeClient. So the most prominent example would be @sentry/node or any SDK inheriting from @sentry/node. According to the issue, you're using @sentry/react which uses BrowserClient and hence doesn't expose this method. ~Are you using a server Sentry SDK in addition?~ The stack trace tells me, you're also using @sentry/node. Would you mind sharing a bit more about your SSR setup?

Yes, using @sentry/node too.

"@sentry/node": "8.8.0",

Sentry.init({
  enabled: process.env.SENTRY_SERVER_ENABLED !== 'false',
  dsn,
  environment: nodeEnv,
  release: appRelease,
  ignoreErrors: ['Failed to fetch', 'Connection disconnected', 'Network request failed', 'NetworkError', 'withrealtime/messaging'],
  integrations: [
    Sentry.captureConsoleIntegration(),
    Sentry.extraErrorDataIntegration(5),
    nodeProfilingIntegration(),
  ],
  sampleRate: Number(process.env.SENTRY_SERVER_SAMPLE_RATE) || 0.1,
  tracesSampleRate: Number(process.env.SENTRY_SERVER_TRACES_SAMPLE_RATE) || 0.1,
  profilesSampleRate: Number(process.env.SENTRY_SERVER_PROFILES_SAMPLE_RATE) || 0.1,
  normalizeDepth: 5,
});

Dima-Dim avatar Jun 11 '24 13:06 Dima-Dim

I don't know anything about your SSR setup but what I think is happening is that you try to bundle the client-side @sentry/react into server side code or that somehow, the Node SDK is initialized but the browser client is already active from an earlier React SDK initialization on the server.

To debug this further, please provide detailed reproduction steps or - even better - a minimal reproduction example. Thanks!

Lms24 avatar Jun 11 '24 20:06 Lms24

I don’t even know what to provide, but I can say that this does not happen with the 7.110.1 version.

Dima-Dim avatar Jun 12 '24 03:06 Dima-Dim

The error disappears if either do not use Sentry.setupExpressErrorHandler(app), or if do not use Sentry for the client '@sentry/react'. If both are used, I get an error client._captureRequestSession is not a function on SSR. On the client (browser) there are no errors.

Dima-Dim avatar Jun 12 '24 06:06 Dima-Dim

This makes generally sense but we don't know yet what kind of SSR setup you have (for example, are you using a framework like NextJS, something like Vite SSR or something custom?). This is important to know because it likely shows how this colission of the Node and React SDKs could happen.

To fix this, we need to know how we can reproduce this issue. So please provide

  1. either code and exact steps what to do to get to this error
  2. or a small repo (or zip file) with a minimal reproducible example that triggers this error.

Lms24 avatar Jun 12 '24 06:06 Lms24

I can't provide the application code yet, but judging by what I see in the issues section of Sentry, errors are coming there from node, although the code for connecting node is commented out.

Dima-Dim avatar Jun 20 '24 05:06 Dima-Dim

I really think this happens because you are accidentally bundling code that is intended to run in Node.js into the client bundle. Try to make sure that nothing in your clientside code points to your server code.

Even though we'd love to help further without additional information, I think some kind of reproduction or the actual code is necessary for us to look into this more deeply!

lforst avatar Jun 21 '24 10:06 lforst

I have the same problem, but in a Nuxt 3 module.

/module.ts

import {
  defineNuxtModule,
  addPlugin,
  createResolver,
  addServerPlugin,
} from "@nuxt/kit";

// Module options TypeScript interface definition
export interface ModuleOptions {}

export default defineNuxtModule<ModuleOptions>({
  meta: {
    name: "sentry-module",
    configKey: "sentryModule",
  },
  // Default configuration options of the Nuxt module
  defaults: {},
  setup(_options, _nuxt) {
    const { resolve } = createResolver(import.meta.url);

    addPlugin(resolve("./runtime/plugin"));

    addServerPlugin(resolve("./runtime/server/plugin"));
  },
});

runtime/plugin.ts

import { defineNuxtPlugin } from "#imports";
import * as Sentry from "@sentry/vue";

export default defineNuxtPlugin((nuxtApp) => {
  const dsn = process.env?.SENTRY_DSN;

  if (!dsn) {
    console.warn(
      "Sentry DSN not set, skipping Sentry initialization - client."
    );
    return;
  }

  const frontendHostRegex = new RegExp(
    `^https:\/\/${process.env.FRONTEND_HOST}`
  );

  Sentry.init({
    app: nuxtApp.vueApp,
    dsn,
    logErrors: true,
    release: `"${process.env.npm_package_name}@${process.env.npm_package_version}"`,
    environment: process.env.NODE_ENV,
    integrations: [
      Sentry.browserTracingIntegration(),
      Sentry.replayIntegration({
        maskAllText: false,
        blockAllMedia: false,
      }),
    ],
    // Performance Monitoring
    tracesSampleRate: 1.0, //  Capture 100% of the transactions
    // Set 'tracePropagationTargets' to control for which URLs distributed tracing should be enabled
    tracePropagationTargets: ["localhost", frontendHostRegex],
    // Session Replay
    replaysSessionSampleRate: 0.1, // This sets the sample rate at 10%. You may want to change it to 100% while in development and then sample at a lower rate in production.
    replaysOnErrorSampleRate: 1.0, // If you're not already sampling the entire session, change the sample rate to 100% when sampling sessions where errors occur.
  });
});

runtime/server/plugin.ts

import { defineNitroPlugin } from "#imports";
import { H3Error } from "h3";
import * as Sentry from "@sentry/node";
import { nodeProfilingIntegration } from "@sentry/profiling-node";

export default defineNitroPlugin((nitroApp) => {
  const dsn = process.env?.SENTRY_DSN;

  if (!dsn) {
    console.warn("Sentry DSN not set, skipping Sentry initialization - server");
    return;
  }

  const frontendHostRegex = new RegExp(
    `^https:\/\/${process.env.FRONTEND_HOST}`
  );

  Sentry.init({
    dsn,
    integrations: [
      // Add our Profiling integration
      nodeProfilingIntegration(),
    ],
    release: `"${process.env.npm_package_name}@${process.env.npm_package_version}"`,
    environment: process.env.NODE_ENV,
    // Performance Monitoring
    tracesSampleRate: 0.2,
    // Set 'tracePropagationTargets' to control for which URLs distributed tracing should be enabled
    tracePropagationTargets: ["localhost", frontendHostRegex],
    // Set sampling rate for profiling - this is relative to tracesSampleRate
    profilesSampleRate: 0.2,
  });

  nitroApp.hooks.hook("error", (error) => {
    // Do not handle 404s and 422s
    if (error instanceof H3Error) {
      if (error.statusCode === 404 || error.statusCode === 422) {
        return;
      }
    }

    Sentry.captureException(error);
  });

  nitroApp.hooks.hook("request", (event) => {
    event.context.$sentry = Sentry;
  });

  nitroApp.hooks.hookOnce("close", async () => {
    await Sentry.close(2000);
  });
});

suku-kahanamoku avatar Jul 30 '24 15:07 suku-kahanamoku

@suku-kahanamoku also in your case, the reason is likely that you're bundling @sentry/node code into the client or perhaps @sentry/vue code into server JS files. I recommend checking for that.

You might want to check out our official @sentry/nuxt SDK. We're still actively working on this SDK (#9095) but we'd greatly appreciate some feedback if you want to give it a try.

For us to debug this, please provide a minimal reproduction example. Thank you!

Lms24 avatar Jul 31 '24 08:07 Lms24

I had a similar issue with the SvelteKit SDK and Vite when attempting to use replayIntegration().

I kept having the error [vite] Error when evaluating SSR module /src/hooks.client.ts: |- TypeError: __vite_ssr_import_0__.replayIntegration is not a function

In my case with SvelteKit and Vite, the solution was to add an environment guard (if (typeof window !== 'undefined')) in my hooks.client.ts file to ensure that it doesn't run on the server.

// hooks.client.ts
import * as Sentry from '@sentry/sveltekit';

if (typeof window !== 'undefined') {
  import('@sentry/sveltekit').then(Sentry => {
  dsn: '__DSN__',
  tracesSampleRate: 1.0,
  replaysSessionSampleRate: 0.1,
  replaysOnErrorSampleRate: 1.0,
  integrations: [Sentry.replayIntegration()],
});
});
}

othmanesghir avatar Aug 01 '24 12:08 othmanesghir

@othmanesghir sorry but this again looks like a different issue to me. Also I find this a bit weird given that the client hooks in SvelteKit should really only run in the client. If you can provide a minimal reproduction, please open a new issue.

Lms24 avatar Aug 01 '24 15:08 Lms24

In fact, I'm going to close this issue because we're now talking about three different frameworks and so far haven't received a minimal reproduction that reproduces the initial bug report. So far, we don't have concrete evidence that this is an SDK bug and not rather a bundling configuration issue.

To anyone following this issue: Please open a new one with a minimal reproducible exmaple so that we can properly debug this. Also, I'm happy to reopen this issue if there's a minimal repro for the original problem.

Thank you :)

Lms24 avatar Aug 01 '24 15:08 Lms24

I put Sentry.init inside an if condition that checks for the client, and now it works. ` import { defineNuxtPlugin, useRuntimeConfig } from "#imports"; import * as Sentry from "@sentry/vue";

export default defineNuxtPlugin((nuxtApp) => { const config = useRuntimeConfig(); const dsn = config.public?.SENTRY_DSN as string;

if (!dsn) { console.warn( "Sentry DSN not set, skipping Sentry initialization - client." ); return; }

const frontendHostRegex = new RegExp( ^https:\/\/${config.public?.FRONTEND_HOST} );

if (import.meta.client) { Sentry.init({ app: nuxtApp.vueApp, dsn, logErrors: true, }); } });

`

Thanks everyone for the advice.

suku-kahanamoku avatar Aug 02 '24 10:08 suku-kahanamoku

We have the same problem!

node server with @sentry/node to run the Vue app Vue app with @sentry/vue

phlegx avatar Oct 25 '24 19:10 phlegx

Hi please be aware that closed issues don't necessarily receive the same level of attention as open ones. I will repeat what I said already multiple times:

If anyone following this issue can provide a minimal reproducible example of this problem, please open a new issue and we'll be happy to look into it. Considering we have various SDKs, frameworks and hence vastly diverse build setups this issue is not actionable for us.

Lms24 avatar Oct 28 '24 08:10 Lms24