Skip to content

Reproduction for sentry-javascript#17742#23

Open
nicohrubec wants to merge 5 commits intomainfrom
repro/sentry-javascript-17742
Open

Reproduction for sentry-javascript#17742#23
nicohrubec wants to merge 5 commits intomainfrom
repro/sentry-javascript-17742

Conversation

@nicohrubec
Copy link
Member

@nicohrubec nicohrubec commented Feb 20, 2026

Summary

Reproduces sentry-javascript#17742 — breadcrumbs from NestJS background jobs leak into HTTP request error events.

Background jobs run outside the HTTP request context, so they add breadcrumbs to the default isolation scope. When a new HTTP request arrives, httpServerIntegration clones the default scope via getIsolationScope().clone() — inheriting all stale breadcrumbs from background jobs.

Background Job Frameworks Covered

Framework Decorator External Dep Env Var Leak Confirmed
@nestjs/schedule @Interval None Always active Yes
@nestjs/event-emitter @OnEvent None Always active Yes
@nestjs/bullmq @Processor Redis REDIS_URL Yes
nestjs-graphile-worker @Task PostgreSQL DATABASE_URL Yes

Root Cause

In packages/node-core/src/integrations/http/httpServerIntegration.ts:185:

const isolationScope = getIsolationScope().clone();

This clones the default isolation scope, which has been polluted by background job breadcrumbs.

How to Run

cd sentry-javascript/17742
cp .env.example .env  # then add your SENTRY_DSN
npm install
npm run test:repro

Optionally set REDIS_URL=redis://localhost:6379 and/or DATABASE_URL=postgres://user:pass@localhost:5432/dbname to also test BullMQ and Graphile Worker leaking.

Expected Output

=== Sentry Event Breadcrumbs (1 total) ===
  [0] category=http-request, message=About to trigger an error in HTTP handler

  No leaked breadcrumbs detected (isolation working).

Actual Output (all 4 frameworks enabled)

*** BUG CONFIRMED: Breadcrumbs leaked from background jobs! ***
  Leaked: schedule-job: 5, event-job: 4, bullmq-job: 3, graphile-job: 2

Setup Details

  • Follows official Sentry NestJS docs — uses SentryModule.forRoot(), SentryGlobalFilter as APP_FILTER
  • Errors are thrown naturally (no manual captureException)
  • BullMQ and Graphile Worker are conditionally loaded based on env vars

🤖 Generated with Claude Code

Demonstrates breadcrumb leaking between NestJS requests due to missing
request isolation scope. Breadcrumbs from earlier requests appear on
later error events.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add SentryGlobalFilter as APP_FILTER provider
- Throw Error instead of manually calling captureException()

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
nicohrubec and others added 3 commits February 20, 2026 11:15
Rewrote reproduction to demonstrate the actual root cause: background
jobs (cron/graphile-worker/BullMQ) run outside HTTP request context and
pollute the default isolation scope. When httpServerIntegration clones
this scope for new requests, it inherits stale breadcrumbs.

Added test-repro.sh for one-command reproduction.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add breadcrumb leaking reproductions for:
- @nestjs/schedule (@interval) - always active
- @nestjs/event-emitter (@onevent) - always active
- @nestjs/bullmq (@processor) - requires REDIS_URL
- nestjs-graphile-worker (@task) - requires DATABASE_URL

Both schedule and event-emitter confirmed leaking breadcrumbs
into HTTP request error events.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The graphile-worker runner wasn't being started, so tasks were queued
but never processed. Now all 4 frameworks confirmed leaking:
schedule-job, event-job, bullmq-job, graphile-job.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

// eslint-disable-next-line @typescript-eslint/no-var-requires
const { BullModule } = require("@nestjs/bullmq");
imports.push(
BullModule.forRoot({ connection: { url: process.env.REDIS_URL } })
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BullMQ connection silently ignores invalid url property

Medium Severity

The BullModule.forRoot({ connection: { url: process.env.REDIS_URL } }) call passes a url property in the connection options, but ioredis's RedisOptions does not support a url property (the feature request was explicitly rejected in ioredis#871). The url field is silently ignored, and ioredis defaults to localhost:6379. This means the BullMQ test case only works by coincidence when Redis happens to be on localhost, and will silently connect to the wrong server for any other REDIS_URL value. The connection URL needs to be parsed into host/port/password fields or an ioredis instance created from the URL string.

Fix in Cursor Fix in Web

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant