Skip to content

sentry 0.45.0 library commands retain SIGTERM listeners under VERCEL #1692

Closed

Description

@getsliced

sentry 0.45.0 library commands retain SIGTERM listeners under VERCEL

Fault

Repeated in-process library commands add SIGTERM handlers under VERCEL. The source-map uploader in @sentry/nextjs 11.8.0 uses this API. Bite's Vercel builds report 11 SIGTERM listeners during the client pass, while source-map uploads still succeed.

Reproduction and measured results

Measured 2026-10-28 on Linux x64, Node 24.18.0, locked sentry 0.45.0 from Bite Preview edfe7a74938b87fc8dc366b9227ffb6bdb3ffd08. A fresh process performs 15 successful sdk.sourcemap.inject({directory}) calls on synthetic JavaScript and a source map; a second fresh process repeats with VERCEL=1. Both verify the injected debugId= marker. No auth token or DSN is needed for injection.

  • Without VERCEL: SIGTERM counts remain 0 after every completed call; adds 0, removals 0, warnings 0.
  • With VERCEL=1: counts rise 1 through 15 after completed calls; adds 15, removals 0; the actual MaxListenersExceededWarning occurs at 11.
  • Both source-map injection sequences succeed. This establishes retention after sequential completion, not just overlapping live operations.
  • Executed through the repaired Quantum host gate after >=120 seconds of uninterrupted CPU<40%, no competing workloads, available memory>=8192 MiB; command exit 0. Full gate samples and registration stacks retained outside Git. Initial pre-repair attempt was stopped before any reproduction ran because the matcher missed node-24; that host defect is tracked separately in getsliced/bite#1065. No telemetry setting is changed, the default listener limit stays 10, and no warning is suppressed.

Source ownership

  • @sentry/bundler-plugins 11.8.0 src/core/cli.ts: SentryCliAdapter uses createSentrySDK; source-map inject/upload, release operations and getServerUrl invoke library commands in the build process.
  • sentry 0.45.0 packages/cli/src/lib/sdk-invoke.ts executeWithCapture calls withTelemetry in library mode for each command, then flushes telemetry.
  • packages/cli/src/lib/telemetry.ts withTelemetry calls initSentry per invocation. initSentry calls getClient()?.close(0) before Sentry.init.
  • sentry 0.45.0 bundles @sentry/node-core 10.63.0. Its packages/node-core/src/light/sdk.ts:129-136 registers an anonymous process.on('SIGTERM') handler per init when process.env.VERCEL is set. The handler closes over that client, with no paired removal in this path.
  • The installed sentry/dist/index.cjs contains the same branch. Bite's top-level @sentry/node 11.8.0 has a separate singleton Vercel handler; changing only that top-level package does not replace the CLI's bundled code.

Sources:
https://github.com/getsentry/cli/blob/03f636f8d1fe6553acf22595eb029ddc8efc79eb/packages/cli/src/lib/sdk-invoke.ts
https://github.com/getsentry/cli/blob/03f636f8d1fe6553acf22595eb029ddc8efc79eb/packages/cli/src/lib/telemetry.ts
https://github.com/getsentry/cli/blob/03f636f8d1fe6553acf22595eb029ddc8efc79eb/packages/cli/package.json
https://github.com/getsentry/sentry-javascript/blob/10.63.0/packages/node-core/src/light/sdk.ts#L129-L136

Requested upstream repair and acceptance

Manage the bundled SDK's Vercel listener lifecycle across library invocations, preserving telemetry and signal flushing. Verify successful and failed sequential library commands leave bounded listener counts, actual repeated inject/upload operations succeed, and a Next.js webpack build under VERCEL no longer warns while uploading all client/server/edge maps. A newer top-level SDK alone cannot update the already-bundled CLI SDK. No performance claim is made from these logs.

Scope and limits

Bite is unchanged. This report does not prove a fixed uploader or a new successful authenticated upload; existing build observations show successful uploads with the warning. Local credentials for authenticated uploads are absent. Do not increase the global listener limit or disable telemetry/source maps as a workaround.

Related upstream work: getsentry/sentry-javascript#25146 addresses repeated init in the newer Node SDK. This report concerns the older node-core/light code embedded in sentry 0.45.0, independently of the app's installed SDK. The CLI package manifest at the inspected current toolkit commit 8860f39 still lists node-core 10.63.0; no runtime assertion about an unreleased toolkit build is made.

Reproduction script

This reproduction targets Linux/POSIX and hardcodes /tmp. Save as lifecycle.cjs in a project with sentry@0.45.0 installed, then run node lifecycle.cjs (the child processes enable --trace-warnings). No credentials are required. Exit 0 confirms command completion and a detected injection marker; listener counts and warning counts are reported, not asserted.

const { createRequire } = require('node:module');
const { spawnSync } = require('node:child_process');
const fs = require('node:fs');
const path = require('node:path');
const req = createRequire(process.cwd() + '/package.json');
if (!process.argv.includes('--scenario')) {
  for (const vercel of [false, true]) {
    const env = { ...process.env };
    delete env.VERCEL;
    if (vercel) env.VERCEL = '1';
    const child = spawnSync(process.execPath, ['--trace-warnings', __filename, '--scenario'], { env, stdio: 'inherit' });
    if (child.status !== 0) process.exit(child.status || 1);
  }
} else {
  const events = [];
  const counts = [];
  let warnings = 0;
  process.on('newListener', (name) => {
    if (name === 'SIGTERM') events.push({ kind: 'add', count: process.listenerCount(name) + 1, stack: new Error('SIGTERM registration').stack });
  });
  process.on('removeListener', (name) => {
    if (name === 'SIGTERM') events.push({ kind: 'remove', count: process.listenerCount(name) });
  });
  process.on('warning', (warning) => {
    if (warning.name === 'MaxListenersExceededWarning') {
      warnings++;
      console.log('WARNING', warning.stack);
    }
  });
  (async () => {
    const { createSentrySDK } = req('sentry');
    const fixture = fs.mkdtempSync('/tmp/bite-893-inject-');
    const js = path.join(fixture, 'example.js');
    fs.writeFileSync(js, 'console.log("synthetic source-map fixture");\n//# sourceMappingURL=example.js.map\n');
    fs.writeFileSync(js + '.map', JSON.stringify({ version: 3, sources: ['example.ts'], sourcesContent: ['console.log("synthetic source-map fixture");'], names: [], mappings: 'AAAA', file: 'example.js' }));
    const sdk = createSentrySDK({ cwd: fixture });
    const start = process.listenerCount('SIGTERM');
    console.log('SCENARIO', JSON.stringify({ vercel: !!process.env.VERCEL, start, maxListeners: process.getMaxListeners() }));
    for (let i = 1; i <= 15; i++) {
      // This is a real source-map operation used by SentryCliAdapter; no token required.
      await sdk.sourcemap.inject({ directory: fixture });
      counts.push(process.listenerCount('SIGTERM'));
    }
    await new Promise(resolve => setImmediate(resolve));
    const injected = fs.readFileSync(js, 'utf8').includes('debugId=');
    console.log('RESULT', JSON.stringify({ vercel: !!process.env.VERCEL, start, counts, warnings, injected, adds: events.filter(e => e.kind === 'add').length, removes: events.filter(e => e.kind === 'remove').length }));
    console.log('EVENTS', JSON.stringify(events, null, 2));
    if (!injected) process.exitCode = 1;
  })().catch(error => { console.error(error); process.exitCode = 1; });
}

The warning stack begins:

MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 SIGTERM listeners added to [process]. MaxListeners is 10.
    at process.addListener (node:events:608:10)
    at Afe (<project>/node_modules/sentry/dist/index.cjs:85:2404)
    at zP (<project>/node_modules/sentry/dist/index.cjs:85:1815)
    at mEe (<project>/node_modules/sentry/dist/index.cjs:204:4244)
    at hTt (<project>/node_modules/sentry/dist/index.cjs:204:2230)
    at bat (<project>/node_modules/sentry/dist/index.cjs:7328:7736)

Downstream build observations (successful uploads alongside this warning): https://github.com/getsliced/bite/issues/893 . They do not establish fixed behavior, and the minimal reproduction above sends no source-map network upload.

Activity

  1. linear-code commented on Oct 28, 2026

    @linear-code
  2. added a commit that references this issue on Oct 28, 2026
    6eda02c
  3. added a commit that references this issue on Oct 28, 2026
    69eb255
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions