You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Hey @sagrawal31 thanks for letting us know! I'll close this issue for now to maintain a clean issue feed but please feel free to ping me whenever you have a working reproduction and then we'll reopen this. Thanks!
Thank you @Lms24. I spent my last 2 days converting my test NestJS project as similar (like wrapping to promise, calling Sentry at almost the same places, etc.) to our production code, but it wasn't helping.
So, I took a different approach. I started removing modules and code one by one from our vast production code and started testing the leak, and I'm glad I succeeded. Here is a fresh NestJS code to reproduce the same: https://github.com/letscooee/nestjs-sentry-test
Steps to reproduce
Clone the repo git clone https://github.com/letscooee/nestjs-sentry-test.git
Set an environment variable SENTRY_DSN or modify sentry.service.ts directly for the DSN.
Run npm run start:dev and server should be up at 3000 port.
Run the following requests:
# /foo endpoint will set a tag and user and capture an "Error1" issue on Sentry
curl --header "content-type: application/json" http://localhost:3000/foo
# /bar endpoint will not set any tags and user and capture an "Error2" issue on Sentry
curl --header "content-type: application/json" http://localhost:3000/bar
Expected behaviour
The second request should not leak on the Sentry request
Actual behaviour
The tag and user are leaking to the second request as well.
Workaround I figured
Wrapping the SentryInterceptor#intercept method code with return Sentry.withIsolationScope(async () => {}) makes it work.
Actual fix that I don't understand
If you check my last commit (letscooee/nestjs-sentry-test@2a99b2f), I moved the Sentry.init code from main.ts initialisation to the constructor initialisation of SentryService. Because of this change, the scope started to leak in the requests. The point I didn't understand is that fundamentally, Sentry is being initialised at a later point of time that's the only difference, so why does the request isolation start breaking? That's where I need your expertise.
Hey @sagrawal31 thanks a lot for the great reproduction! I was able to reproduce it instantly.
You already correctly identified that you get scope leakage because of Sentry initializing too late in the game. Unfortunately, this is expected behaviour or rather, an unfortunate consequence of how OpenTelemetry instruments NodeJS applications.
Fundamentally the thing that's failing is that our SDK (or the Otel SDK under the hood) needs to instrument node:http(s). We do this to capture request spans but even more importantly to isolate requests, more specifically to set an isolation scope as you did in your workaround.
To instrument libraries like http the SDK basically intercepts require('http') calls. To do that, it needs to be initialized before the first such require call. If you move the Sentry.init code to your service, this is too late as the NestJS server is already setting up (afaik by default an Express server which internally uses http).
That's the reason why our docs clearly state that the SDK must be initialized first thing in your main.ts file. I hope this makes sense.
Note, if you're transpiling to ESM (i.e. your built code has import statements instead of require calls) make sure to follow these instructions instead.
So to conclude, this isn't a bug but unfortunate, expected behaviour. I recommend following our docs for setup and avoiding a late-init of Sentry. If you cannot at all avoid this, there's a compromise to preload the instrumentation part of the SDK and only init the SDK itself later. Follow this guide for it.
Hi @Lms24, apologies for not replying immediately. I read your comments right after you posted and I went testing out something else.
Thank you for testing my test repository and reverting back with the detailed investigation, screenshot, and amazing explanation. I loved how dedicated you are to your work. I showed your comments to my team members as well (@AbhishekTaparia @ashishgkwd534). They are much appreciated!
And how silly I was to miss the part of patching the http(s) which would not be possible if the SDK is being initialised lately. That first mention of http patching cleared my mind. Thanks a lot!
Also, how did you enable the Sentry logging? I tried to do it myself with the debug flag while investigating.
Hey @sagrawal31 thanks for the kind words, appreciate them a lot! And please, no need to apologize, we get this question a lot. Your example was just perfect to explain things in detail :)
Also, how did you enable the Sentry logging? I tried to do it myself with the debug flag while investigating.
Sentry.init({// your other options, dsn, etc..debug: true,})
In some SDKs, you might need to specifically enabled debug output bundling (e.g. Nett.js) but for @sentry/nestjs this should be enough and it's exactly what I did.
I'm going to close this issue because I believe everything was answered (and improving debug logging was extracted to #15986). Please let me know if you have more questions, happy to help :)
Activity
[-]Scopes are leaking[/-][+]Scopes are leaking in NestJS requests[/+]sagrawal31 commentedon Apr 1, 2025
I'm trying to reproduce this on a fresh NestJS project and couldn't reproduce it. Please don't spend time on it yet. Will keep you updated.
Lms24 commentedon Apr 1, 2025
Hey @sagrawal31 thanks for letting us know! I'll close this issue for now to maintain a clean issue feed but please feel free to ping me whenever you have a working reproduction and then we'll reopen this. Thanks!
sagrawal31 commentedon Apr 4, 2025
Thank you @Lms24. I spent my last 2 days converting my test NestJS project as similar (like wrapping to promise, calling Sentry at almost the same places, etc.) to our production code, but it wasn't helping.
So, I took a different approach. I started removing modules and code one by one from our vast production code and started testing the leak, and I'm glad I succeeded. Here is a fresh NestJS code to reproduce the same: https://github.com/letscooee/nestjs-sentry-test
Steps to reproduce
git clone https://github.com/letscooee/nestjs-sentry-test.gitsentry.service.tsdirectly for the DSN.npm run start:devand server should be up at 3000 port.Expected behaviour
The second request should not leak on the Sentry request

Actual behaviour
The tag and user are leaking to the second request as well.

Workaround I figured
Wrapping the
SentryInterceptor#interceptmethod code withreturn Sentry.withIsolationScope(async () => {})makes it work.Actual fix that I don't understand
If you check my last commit (letscooee/nestjs-sentry-test@2a99b2f), I moved the
Sentry.initcode frommain.tsinitialisation to the constructor initialisation ofSentryService. Because of this change, the scope started to leak in the requests. The point I didn't understand is that fundamentally, Sentry is being initialised at a later point of time that's the only difference, so why does the request isolation start breaking? That's where I need your expertise.Lms24 commentedon Apr 4, 2025
Hey @sagrawal31 thanks a lot for the great reproduction! I was able to reproduce it instantly.
You already correctly identified that you get scope leakage because of Sentry initializing too late in the game. Unfortunately, this is expected behaviour or rather, an unfortunate consequence of how OpenTelemetry instruments NodeJS applications.
Fundamentally the thing that's failing is that our SDK (or the Otel SDK under the hood) needs to instrument
node:http(s). We do this to capture request spans but even more importantly to isolate requests, more specifically to set an isolation scope as you did in your workaround.To instrument libraries like
httpthe SDK basically interceptsrequire('http')calls. To do that, it needs to be initialized before the first suchrequirecall. If you move theSentry.initcode to your service, this is too late as the NestJS server is already setting up (afaik by default an Express server which internally useshttp).That's the reason why our docs clearly state that the SDK must be initialized first thing in your
main.tsfile. I hope this makes sense.Note, if you're transpiling to ESM (i.e. your built code has
importstatements instead ofrequirecalls) make sure to follow these instructions instead.1 remaining item
Lms24 commentedon Apr 4, 2025
So to conclude, this isn't a bug but unfortunate, expected behaviour. I recommend following our docs for setup and avoiding a late-init of Sentry. If you cannot at all avoid this, there's a compromise to preload the instrumentation part of the SDK and only init the SDK itself later. Follow this guide for it.
Let me know if you have any other questions.
mydea commentedon Apr 7, 2025
I created an issue to see if we can warn for this case better in the SDK: #15986
sagrawal31 commentedon Apr 7, 2025
Hi @Lms24, apologies for not replying immediately. I read your comments right after you posted and I went testing out something else.
Thank you for testing my test repository and reverting back with the detailed investigation, screenshot, and amazing explanation. I loved how dedicated you are to your work. I showed your comments to my team members as well (@AbhishekTaparia @ashishgkwd534). They are much appreciated!
And how silly I was to miss the part of patching the
http(s)which would not be possible if the SDK is being initialised lately. That first mention ofhttppatching cleared my mind. Thanks a lot!Also, how did you enable the Sentry logging? I tried to do it myself with the
debugflag while investigating.Lms24 commentedon Apr 7, 2025
Hey @sagrawal31 thanks for the kind words, appreciate them a lot! And please, no need to apologize, we get this question a lot. Your example was just perfect to explain things in detail :)
In some SDKs, you might need to specifically enabled debug output bundling (e.g. Nett.js) but for
@sentry/nestjsthis should be enough and it's exactly what I did.I'm going to close this issue because I believe everything was answered (and improving debug logging was extracted to #15986). Please let me know if you have more questions, happy to help :)