Is there an existing issue for this?
How do you use Sentry?
Sentry Saas (sentry.io)
Which SDK are you using?
@sentry/deno
SDK Version
10.48.0 (bug was introduced alongside setupWeightBasedFlushing)
Framework Version
No response
Link to Sentry event
No response
Reproduction Example/SDK Setup
import * as Sentry from '@sentry/deno';
Sentry.init({
dsn: '', // no DSN... _transport is undefined
enableLogs: true,
});
Sentry.logger.info('hello');
await Sentry.flush(2000);
// Expected: all pending work drained, no leaked handles
// Actual: a setTimeout from setupWeightBasedFlushing is still pending
Minimal reproduction as a Deno test (fails with "Leaks detected: timers were started in this test, but never completed"):
// repro.test.ts
// deno test --allow-env --allow-net repro.test.ts
import * as Sentry from 'npm:@sentry/deno@10.48.0';
Deno.test('flush does not clear weight-based flush timer without transport', async () => {
Sentry.init({ dsn: '', enableLogs: true });
Sentry.logger.info('hello');
await Sentry.flush(2000);
});
Steps to Reproduce
- Initialize a Sentry client with no DSN (or any configuration that leaves
_transport undefined), with enableLogs: true or any code path that records a metric via Sentry.metrics.*.
- Capture at least one log or metric so
setupWeightBasedFlushing starts its 5-second idle setTimeout.
- Call
Sentry.flush() (or client.flush()).
- Observe that the
setTimeout handle is still pending after flush() resolves.
Expected Result
Client.flush() drains the log and metric buffers and clears the weight-based flusher's idle timer, regardless of whether a transport is configured. On runtimes with strict handle/op tracking (Deno test runner, Node --trace-uncaught style harnesses), the process or test has no lingering timer after flush() returns.
Actual Result
Client.flush() returns immediately when !this._transport, without emitting the 'flush' event. The listener installed by setupWeightBasedFlushing (packages/core/src/client.ts) is the only thing that clears flushTimeout, so the idle timer keeps running until the 5-second DEFAULT_FLUSH_INTERVAL elapses (or indefinitely, in environments where the timer is unref'd but the test sanitizer still tracks it).
Deno's test sanitizer surfaces this as:
error: Leaks detected:
- 2 timers were started in this test, but never completed.
at setTimeout (node:timers:14:10)
at .../@sentry/core/10.48.0/build/esm/client.js:108:9
at uniqueCallback (.../@sentry/core/10.48.0/build/esm/client.js:551:41)
at DenoClient.emit (.../@sentry/core/10.48.0/build/esm/client.js:572:17)
Additional Context
-
Root cause is the early return in Client.flush():
public async flush(timeout?: number): PromiseLike<boolean> {
const transport = this._transport;
if (!transport) {
return true; // <-- returns before emitting 'flush'
}
this.emit('flush');
// ...
}
The setupWeightBasedFlushing listeners registered on 'flushLogs'/'flushMetrics' (triggered via the 'flush' hook) are what clearTimeout(flushTimeout)... so skipping the emit leaves the timer permanently armed.
-
Affects any environment that legitimately runs without a DSN (unit tests, CI smoke tests, development mode), and is most visible on Deno where the test runner's op sanitizer fails any test with a lingering timer.
-
We originally hit this in Supabase Deno edge function tests where the shared harness calls Sentry.init({ dsn: '', enableLogs: true }) and records metrics per request, then calls Sentry.flush(2000) in the request finalizer.
-
Fix is trivial... move this.emit('flush') above the !transport early return. PR incoming.
Priority
React with 👍 to help prioritize this issue. Please use comments to provide useful context, avoiding +1 or me too, to help us triage it.
Is there an existing issue for this?
How do you use Sentry?
Sentry Saas (sentry.io)
Which SDK are you using?
@sentry/deno
SDK Version
10.48.0 (bug was introduced alongside setupWeightBasedFlushing)
Framework Version
No response
Link to Sentry event
No response
Reproduction Example/SDK Setup
Minimal reproduction as a Deno test (fails with "Leaks detected: timers were started in this test, but never completed"):
Steps to Reproduce
_transportundefined), withenableLogs: trueor any code path that records a metric viaSentry.metrics.*.setupWeightBasedFlushingstarts its 5-second idlesetTimeout.Sentry.flush()(orclient.flush()).setTimeouthandle is still pending afterflush()resolves.Expected Result
Client.flush()drains the log and metric buffers and clears the weight-based flusher's idle timer, regardless of whether a transport is configured. On runtimes with strict handle/op tracking (Deno test runner, Node--trace-uncaughtstyle harnesses), the process or test has no lingering timer afterflush()returns.Actual Result
Client.flush()returns immediately when!this._transport, without emitting the'flush'event. The listener installed bysetupWeightBasedFlushing(packages/core/src/client.ts) is the only thing that clearsflushTimeout, so the idle timer keeps running until the 5-secondDEFAULT_FLUSH_INTERVALelapses (or indefinitely, in environments where the timer isunref'd but the test sanitizer still tracks it).Deno's test sanitizer surfaces this as:
Additional Context
Root cause is the early return in
Client.flush():The
setupWeightBasedFlushinglisteners registered on'flushLogs'/'flushMetrics'(triggered via the'flush'hook) are whatclearTimeout(flushTimeout)... so skipping the emit leaves the timer permanently armed.Affects any environment that legitimately runs without a DSN (unit tests, CI smoke tests, development mode), and is most visible on Deno where the test runner's op sanitizer fails any test with a lingering timer.
We originally hit this in Supabase Deno edge function tests where the shared harness calls
Sentry.init({ dsn: '', enableLogs: true })and records metrics per request, then callsSentry.flush(2000)in the request finalizer.Fix is trivial... move
this.emit('flush')above the!transportearly return. PR incoming.Priority
React with 👍 to help prioritize this issue. Please use comments to provide useful context, avoiding
+1orme too, to help us triage it.