Skip to content

✨ [DEBUG-6444] Capture Exception Replay snapshots for RUM errors - #5196

Open
watson wants to merge 16 commits into
watson/DEBUG-6444/rum-add-pluginfrom
watson/exception-replay-method-probes
Open

watson wants to merge 16 commits into
watson/DEBUG-6444/rum-add-pluginfrom
watson/exception-replay-method-probes

Conversation

@watson

@watson watson commented Oct 28, 2026 •

Copy link
Copy Markdown
Collaborator

Motivation

DEBUG-6444

Exception Replay shows the arguments a function had when an error passed through it, on the error's stack frames in Error Tracking. Backend errors get it from the tracers, but browser errors have nothing like it. This brings it to browser errors reported by RUM, using the Live Debugger's build-time instrumentation. This first version captures arguments and this only, not local variables.

Changes

  • Capture: code built with the Live Debugger build plugin's new exceptionReplay option calls $dd_catch for every exception that leaves an instrumented function. The SDK captures the arguments and this of the three innermost frames as the exception is thrown, and keeps them with the error in a WeakMap. Errors that RUM never reports are garbage collected with their captures, and nothing is sent for them.
  • Linking to the RUM error: DD_DEBUGGER.init() adds a RUM plugin to the RUM Browser SDK with DD_RUM.addPlugin() (✨ [DEBUG-6444] Let SDKs add RUM plugins after init with addPlugin() #5220), once RUM has loaded, so customers don't change their RUM configuration, and the Live Debugger SDK can load after RUM is initialized. The plugin adds error.debug_info_captured: "true" and _dd.exception_replay (the exception ID, plus the stack index and snapshot ID of each captured frame) to the RUM error event while it's assembled. Each snapshot carries exceptionId, so the UI treats it as an Exception Replay snapshot.
  • Only for errors RUM sends: the plugin holds the snapshots until RUM collects the error event, after beforeSend and the event rate limits. An error that either of them drops sends no snapshots, and doesn't start the one-hour limit for its fingerprint.
  • New RUM plugin hook (RUM core change): RumPluginOnInitOptions.registerEventCollectedHook registers a callback that runs once an event has passed beforeSend and the rate limits, right before it's sent. It's backed by a new eventCollected hook in hooks.ts, triggered in assembly.ts. A new isTrackingConsentGranted() option tells plugins whether tracking consent is granted, including consent set with setTrackingConsent() before init(). Until RUM starts, Exception Replay only captures while it is. With an older RUM SDK that lacks either option or addPlugin(), Exception Replay warns and stays off.
  • Frame indexes: the SDK finds each captured frame's position in error.stack by lining up the call stack taken inside $dd_catch with the error's stack, as parsed by computeStackTrace. Error Tracking attaches snapshots to frames by that position.
  • Redaction: Exception Replay captures redact values with sensitive names, using the tracers' list. Live Debugger probe snapshots are unchanged.
  • Limits: at most 10 new exceptions captured per second, and at most 25 ms per second of capture time on average. Each frame's 10 ms deadline is also capped by the remaining budget, and time spent beyond it is carried over, so capturing pauses until it's made up. An error with the same type and innermost function is reported with snapshots at most once an hour. These limits are separate from the probes' maxSnapshotsPerSecondGlobally, so neither feature can use up the other's.
  • Who's affected: only applications that are built with exceptionReplay, and initialize both the RUM Browser SDK and the Live Debugger SDK. $dd_catch is only defined once RUM has initialized the plugin and the Live Debugger SDK is initialized. Nothing is captured in sessions that RUM doesn't track.
  • No runtime dependency on RUM: the plugin's types are written out in browser-debugger. Specs check at compile time that it's still assignable to RumPlugin, and that the RUM public API still has the onReady() and addPlugin() it uses. browser-rum-core is only a devDependency, because declaring it as a dependency broke yarn build:apps.

This change was written with an AI agent. Please look closely at the frame-index matching in exceptionReplay.ts, the RUM plugin's types, and the new eventCollected hook, which the RUM team should review.

Depends on the rum-events-format PR. @datadog/rum-events-format is pinned to the head commit of DataDog/rum-events-format#458, which adds the new fields. Once that PR merges, the pin has to be bumped to its merge commit before this one merges. The regenerated types also include #454 (Add Unreal as source), already on rum-events-format master.

Stacked on #5220, which adds addPlugin(). This PR's base is #5220's branch until it merges.

Test instructions

  • Unit tests: yarn test:unit --spec packages/browser-debugger/src/domain/exceptionReplay.spec.ts. The plugin, redaction and capture specs sit next to it.
  • End to end: yarn test:e2e -g "Exception Replay". One test checks the snapshots are linked to the RUM error event, the other that an error dropped by beforeSend sends none. The test page uses hand-written code equivalent to what the build plugin generates, so it doesn't need a build-plugins release. Both pass in Chromium, Firefox and WebKit.

Checklist

  • Tested locally
  • Tested on staging
  • Added unit tests for this change.
  • Added e2e/integration tests for this change.
  • Updated documentation and/or relevant AGENTS.md file

Related PRs

Created with Claude Opus 5.5 and Claude Sonnet 5.5 in Claude Code.

Add Exception Replay to the Browser Debugger SDK. Code built with the
Live Debugger build plugin's `exceptionReplay` option calls `$dd_catch`
for every exception that leaves an instrumented function. The SDK
captures the arguments and `this` of the three innermost frames, keeps
them with the error, and only sends them as snapshots when RUM reports
the error. A new RUM plugin, `datadogDebugger.exceptionReplayPlugin()`,
adds `error.debug_info_captured` and `_dd.exception_replay` to the RUM
error event to link it to its snapshots.

Captures redact sensitive names using the tracers' list, are limited to
10 new exceptions per second and one report per error type and
function per hour, and count toward the global snapshot limit.

Environment: Datadog workspace

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@datadog-prod-us1-6

datadog-prod-us1-6 Bot commented Oct 28, 2026 •

Copy link
Copy Markdown

Pipelines  Tests

✨ Unblock PR with BitsAI

❌ Errors

Your PR has failed checks. Please review the issues below and take necessary action before merging.

🚦 2 Pipeline jobs failed

DataDog/browser-sdk | unit-bs: [chrome-desktop] — ❌ 1 test failed · 🔧 Needs a code fix, caused by this PR

View more details · View in GitLab

❌ exceptionReplay should capture an async function awaiting a callee that throws before its first await from Chrome 80.0.3987.132 (Windows 10)
Expected $.length = 1 to equal 2.
Expected $[1] = undefined to equal 1.
Error: Expected $.length = 1 to equal 2.
Expected $[1] = undefined to equal 1.
    at &lt;Jasmine&gt;
    at UserContext.&lt;anonymous&gt; (webpack:///packages/browser-debugger/src/domain/exceptionReplay.spec.ts:309:23 &lt;- /tmp/_karma_webpack_198440/commons.js:73218:29)
DataDog/browser-sdk | unit-bs: [edge] — ❌ 1 test failed · 🔧 Needs a code fix, caused by this PR

View more details · View in GitLab

❌ exceptionReplay should capture an async function awaiting a callee that throws before its first await from Edge 80.0.361.57 (Windows 10)
Expected $.length = 1 to equal 2.
Expected $[1] = undefined to equal 1.
Error: Expected $.length = 1 to equal 2.
Expected $[1] = undefined to equal 1.
    at &lt;Jasmine&gt;
    at UserContext.&lt;anonymous&gt; (webpack:///packages/browser-debugger/src/domain/exceptionReplay.spec.ts:309:23 &lt;- /tmp/_karma_webpack_182998/commons.js:73218:29)

ℹ️ Info

No other issues found (see more)

❄️ No new flaky tests detected

🎯 Code Coverage (details)
• Patch Coverage: 77.31%
• Overall Coverage: 77.30% (-0.02%)

Useful? React with 👍 / 👎

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: df1a364 | Docs | View more details | Give us feedback!

@cit-pr-commenter-54b7da

cit-pr-commenter-54b7da Bot commented Oct 28, 2026 •

Copy link
Copy Markdown

Bundles Sizes Evolution

📦 Bundle Name Base Size Local Size 𝚫 𝚫% Status
Rum Salesforce 191.43 KiB 191.61 KiB +186 B +0.09% ✅
Rum 191.41 KiB 191.59 KiB +186 B +0.09% ✅
Rum Salesforce Profiler 8.35 KiB 8.35 KiB 0 B 0.00% ✅
Rum Profiler 8.35 KiB 8.35 KiB 0 B 0.00% ✅
Rum Salesforce Recorder 32.04 KiB 32.04 KiB 0 B 0.00% ✅
Rum Recorder 32.04 KiB 32.04 KiB 0 B 0.00% ✅
Logs 59.78 KiB 59.78 KiB 0 B 0.00% ✅
Rum Slim 147.53 KiB 147.71 KiB +179 B +0.12% ✅
Worker 24.23 KiB 24.23 KiB 0 B 0.00% ✅
Rum Shopify 221.86 KiB 222.05 KiB +186 B +0.08% ✅
Rum Shopify Profiler 8.35 KiB 8.35 KiB 0 B 0.00% ✅
Rum Shopify Recorder 4.85 KiB 4.85 KiB 0 B 0.00% ✅

watson and others added 4 commits October 29, 2026 10:19
Exception Replay sent an error's snapshots while RUM assembled the
error event, before `beforeSend` and the event rate limits ran. An
error that either of them dropped still sent its snapshots, with no
error event to link them to.

Add an `eventCollected` hook to RUM, triggered once an event has passed
`beforeSend` and the rate limits, and expose it to plugins as
`registerEventCollectedHook`. The Exception Replay plugin still adds
its attributes while the event is assembled, but holds the snapshots
until the hook fires. The one-hour fingerprint limit also starts then.

Also stop capturing in sessions RUM doesn't track, since their errors
are never reported, and fix the async function spec on Safari 14,
which leaves the function's name out of the stack after an `await`.

Environment: Datadog workspace

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The declaration build failed with "Type instantiation is excessively
deep" where the `eventCollected` hook is triggered. Checking that the
domain context fits `DeepReadonly` recursed through the DOM types it
holds. `yarn typecheck` didn't catch it, as it uses another
configuration. The hook's domain context is now a plain
`RumEventDomainContext`.

Environment: Datadog workspace

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ay schema PR

check-schemas regenerates the types from the pinned schema, which
didn't have the Exception Replay fields yet. Pin the head commit of
DataDog/rum-events-format#458 until it merges, then bump to its merge
commit. The regenerated types also pick up #454 (Add Unreal as source),
which is already on rum-events-format master.

Environment: Datadog workspace

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Exception Replay captures on the main thread as exceptions are thrown, and
the 10 ms per-frame deadline alone allowed up to 300 ms per second (10
exceptions with 3 frames each). The deadline also can't interrupt a single
slow step, such as reading the property names of an object with 100k keys.

- Cap capturing at 25 ms per second on average. Each frame's deadline is
  also capped by the remaining budget. Time spent beyond the budget is
  carried over, so capturing pauses until it's made up.
- Stop counting Exception Replay snapshots against the probes'
  maxSnapshotsPerSecondGlobally, so neither feature can starve the other.
  Exception Replay is already limited by its own caps.

Environment: Datadog workspace

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@watson
watson marked this pull request as ready for review October 31, 2026 15:17
@watson
watson requested review from a team as code owners October 31, 2026 15:17
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 31, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-03T14:24:46.754732Z df1a364 New commits
🔒 Security Review ✅ Completed 2026-11-03T14:29:14.826952Z df1a364 New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@watson
watson marked this pull request as draft October 31, 2026 15:24
@watson
watson removed request for a team October 31, 2026 15:24

@datadog-prod-us1-6 datadog-prod-us1-6 Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Bits Code Review: FAIL

Exception Replay can attach arguments to unrelated async stack frames, omit valid captures, and upload sensitive symbol-property values without redaction. Serialization failures and retries of previously dropped errors can also bypass capture limits.

Open Bits AI session

🤖 Bits Code Review · Commit d17501a

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d17501a1aa

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

- Redact properties and map entries with sensitive symbol keys, which
  are captured under their description.
- Capture errors thrown before RUM starts, whose session isn't known
  yet. Only skip sessions that RUM doesn't track once it has started.
- Don't send the snapshots of an error that RUM dropped once another
  error with the same fingerprint has been reported.
- Trigger the `eventCollected` hook before the event is dispatched, as
  documented.
- Charge the capture time budget even when capturing throws.
- Compare only the line of async caller frames, which are located at
  the `await` instead of the call, so outer async frames aren't dropped.
- Match a frame without callers only to a frame of the same function,
  so its snapshot can't land on an unrelated frame of the same script.
- Document that a `beforeSend` removing or reordering frames in
  `error.stack` can misplace snapshots.

Environment: Datadog workspace

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@watson
watson marked this pull request as ready for review November 3, 2026 11:55
…t async stack traces

The older Chrome, Edge, Firefox and Safari versions on BrowserStack
don't record async stack traces, so once `asyncCaller` resumes, its
stack shows no caller and its frame can't be confirmed. The SDK then
leaves it without a snapshot, as intended. Only expect its snapshot
when the browser records async stack traces.

Environment: Datadog workspace

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@datadog-prod-us1-6 datadog-prod-us1-6 Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Bits Code Review: FAIL

Snapshot links can point to the wrong frame in single-line async bundles or to nonexistent frames when a thrown plain object is reported through RUM. Both defects have localized fixes.

Open Bits AI session

🤖 Bits Code Review · Commit 5baae08

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8db607da74

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/browser-debugger/README.md Resolved
- Don't capture before RUM starts while tracking consent isn't granted.
- Only capture `Error` instances: RUM doesn't report the stack of other
  thrown values, so their snapshots would link to frames that aren't
  there.
- Keep function identity when comparing async caller frames by line, so
  two functions on the same line of a minified bundle don't match.
- Report redacted objects as `Object` or `Array`, without reading their
  constructor name, which the redacted object controls.
- Document that RUM and the Live Debugger SDK must send to the same site
  and organization.
- Make the async callee spec hold in browsers that don't show async
  callers on the line of their `await` (Chrome 80, Edge) or don't name
  async functions (Safari 14): check frame positions, and only require
  the caller's snapshot where the browser shows the caller there.

Environment: Datadog workspace

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9cbf27e05e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

watson and others added 2 commits November 3, 2026 12:31
Brings in the addPlugin() RUM API, and main with #5217. The conflict in
preStartRum.ts is resolved by adding registerEventCollectedHook to the
options that both the init plugins and the added plugins get.

Environment: Datadog workspace

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Customers no longer pass a plugin to DD_RUM.init(), so the Live Debugger
SDK doesn't have to load before RUM is initialized. DD_DEBUGGER.init()
adds the Exception Replay plugin with DD_RUM.addPlugin() once the RUM
Browser SDK has loaded, including with the async loading snippet. It
warns if that version of RUM can't add plugins after init.

- Remove exceptionReplayPlugin() from the public API.
- Update the README, and the e2e tests, which no longer have to start
  RUM from DD_DEBUGGER.onReady().

Environment: Datadog workspace

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Environment: Datadog workspace

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@watson
watson changed the base branch from main to watson/DEBUG-6444/rum-add-plugin November 3, 2026 12:58

@datadog-prod-us1-6 datadog-prod-us1-6 Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Bits Code Review: FAIL

Exception Replay can retain arguments captured while effective RUM consent is denied and send them when the same Error is reported after consent is granted. Anonymous async catches can also attach snapshots to unrelated stack frames.

Open Bits AI session

🤖 Bits Code Review · Commit f72c087

@chatgpt-codex-connector

Copy link
Copy Markdown

💡 Codex Review

for (const plugin of pluginsAddedBeforeInit.splice(0)) {
startAddedPlugin(plugin, pluginOnInitOptions)

P2 Badge Defer added plugins until initialization is accepted

issue: When a plugin supplied to init() returns or resolves to false, this loop still initializes plugins queued through addPlugin() before shouldContinue is checked. In the normal debugger-before-RUM load order, that starts the Exception Replay plugin and installs $dd_catch; because RUM never calls onRumStart, its pre-start predicate keeps capturing arguments indefinitely even though RUM will never report them. The same problem occurs when configuration validation later rejects the init, and a subsequent valid init() cannot reinitialize the already-drained plugin with the new configuration.


if (isThenable(onInitResult)) {
onInitResult.then(() => callAddedPluginOnRumStartOnceStarted(plugin), monitorError)
} else {
callAddedPluginOnRumStartOnceStarted(plugin)

P2 Badge Skip onRumStart when an added plugin returns false

issue: When an added plugin's onInit returns false or resolves to false, these branches discard that result and still schedule onRumStart. Although an added plugin must not abort RUM itself, false is the plugin contract's signal that initialization should not continue; calling onRumStart can therefore activate a plugin that detected an unsupported setup or only partially initialized. Treat false like a failed added-plugin initialization and skip that plugin's onRumStart while allowing RUM to continue.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

watson and others added 2 commits November 3, 2026 13:25
Environment: Datadog workspace

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…Replay

Before RUM started, Exception Replay only checked the trackingConsent
init option. It missed consent denied with setTrackingConsent() before
init(), which overrides that option, and so captured arguments while
consent was denied.

- RUM gives plugins isTrackingConsentGranted(), which reads the current
  consent, however it was set.
- Exception Replay uses it until RUM starts, and stays off with a RUM
  version that lacks it.

Environment: Datadog workspace

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bfa04bba24

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

watson and others added 2 commits November 3, 2026 14:46
A function without callers was matched to a frame of the same script
that came earlier in the file whenever one of the two had no function
name. An anonymous function that caught an error created by a named
function of the same script was then linked to that function's frame.

A frame with a name and one without are now from different functions.
Two unnamed functions of the same script can still be mistaken for each
other.

Environment: Datadog workspace

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Environment: Datadog workspace

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@watson

watson commented Nov 3, 2026

Copy link
Copy Markdown
Collaborator Author

Note

🤖 Claude Opus 5.5 responding on behalf of Thomas Watson

Replying to the Codex review above: both findings are fixed in #5220 (26f1779) and merged here in aa5ab4d.

  • Defer added plugins until initialization is accepted: plugins added with addPlugin() now start only once the init() plugins have let init() continue. If one of them aborts init(), the added plugins stay queued for a later init(). A configuration that fails validation doesn't stop them, but it doesn't stop the init() plugins either, since both run their onInit before validation.
  • Skip onRumStart when an added plugin returns false: an added plugin whose onInit returns or resolves to false no longer gets onRumStart, and RUM still continues.

@watson
watson added this pull request to stack #5229 November 3, 2026 14:02
…5220)

Environment: Datadog workspace

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: df1a3640ac

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +260 to +265
const snapshots = exception.pendingSnapshots
exception.pendingSnapshots = undefined
for (const snapshot of snapshots) {
queueExceptionSnapshot(snapshot)
}
recordReport(exception.fingerprint)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Recheck the cooldown before sending pending snapshots

issue: When a beforeSend callback synchronously captures and reports another error with the same fingerprint, the nested event can send first and start the cooldown while this outer event still has pending snapshots. This path sends those outer snapshots without rechecking isCoolingDown(), so both exceptions receive snapshots despite the documented once-per-hour limit. Recheck the fingerprint immediately before queueing the pending snapshots.

Useful? React with 👍 / 👎.

readonly domainContext: RumEventDomainContext<RawRumEvent['type']>
}

export type EventCollectedHook = Hook<EventCollectedHookParams, void>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Prevent collected hooks from suppressing later callbacks

issue: When an earlier plugin's collected callback returns DISCARDED, this Hook type explicitly permits that result and createHook().trigger() stops invoking subsequent callbacks, even though startRumAssembly() ignores the result and still dispatches the RUM event. If Exception Replay registered after that plugin, the error event is sent with snapshot links but its collected callback never queues the snapshots. This notification-style hook should invoke every registered callback rather than inherit assembly-hook discard semantics.

Useful? React with 👍 / 👎.

Comment on lines +101 to +103
registerExceptionReplayPlugin(() =>
rumStarted ? publicApi.getInternalContext() !== undefined : isTrackingConsentGranted()
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Stop pre-start capture when RUM session setup fails

issue: When RUM accepts its configuration but startSessionManager() later resolves without a manager—for example, the default cookie persistence is unavailable—onRumStart is never called, yet this pre-start predicate keeps returning true while consent remains granted. $dd_catch then captures function arguments for every eligible exception indefinitely even though RUM has explicitly disabled event delivery and can never collect those snapshots. Fresh evidence beyond the previously fixed aborted-init path is the asynchronous no-storage return from startSessionManager() after added plugins have already initialized; the plugin needs a terminal initialization-failure signal that disables capture.

Useful? React with 👍 / 👎.

This branch has not been deployed

No deployments
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