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
{{ message }}
Repository navigation
Loader stub silently drops calls outside queued method list, which results in either silent no-ops #21806
The CDN loader stub only queues a fixed set of SDK methods pre-load (init, addBreadcrumb, captureMessage, captureException, captureEvent, configureScope, withScope, showReportDialog). Any SDK call outside this list — such as addIntegration — is silently absent on the window.Sentry proxy before the full bundle loads, causing either silent no-ops or runtime crashes depending on timing.
The correct workaround is wrapping such calls in Sentry.onLoad(...), but the loader provides no mechanism to enforce this, making it easy to write code that works in development (where the bundle may already be loaded) but crashes in production.
Current Behavior
Unrecognized calls on the pre-load proxy are undefined — calling them throws or silently does nothing
addIntegration is a notable gap: it is a common post-init call pattern that the loader stub does not queue
Gap
No TypeScript or runtime guardrail prevents calling unqueued methods before onLoad
The failure mode is timing-dependent and hard to reproduce locally
Solution Brainstorm
Options
Extend the queued method list — add addIntegration (and other commonly used post-init methods) to the pre-load queue so they are replayed after the bundle loads, consistent with how init is handled
Catch-all no-op proxy — intercept any unrecognized property access pre-load and return a no-op function; prevents crashes but silently swallows calls
Catch-all replay proxy — queue all unrecognized calls (not just the fixed list) and attempt replay post-load; broader coverage but requires more careful handling of methods with return values
Option 1 is the lowest-risk and most targeted fix. Option 3 is the most ergonomic for callers but adds complexity to the replay logic.
We talked a bit about this and unfortunately, all of the suggested solutions have drawbacks that make it unlikely for us to implement them. That being said, there's at least a bit of typing help we can add for TS-based setups that still use the loader.
Let me explain our thoughts on the options:
Extend the queued method list - we deliberately chose the current subset of queued APIs. Extending this list is complicated because it's always hard to draw the line. For example, I'd very much challenge that addIntegration is a widely-used API for loader users.
Catch-all no-op proxy: This introduces a lot of uncertainty. Users cannot rely on any Sentry calls anymore. Yes they don't error but nevertheless, they have no effect. I agree that this fulfills the "fail silently" criterion for SDKs, so we can think about it, but it won't solve any legitimate issue for SDK users expecting SDK behaviour (for example when calling Sentry.addIntegration)
Catch-all Replay Proxy: It sounds intriguing but it opens a can of worms for a variety of APIs. The issue of return types was already brought up. For example, right now, the proxied captureException function returns no event id, while the actual captureException returns said id. Another issue are all timing-sensitive APIs. Sentry.start*Span* or logger and metric APIs being the prime example. While we can enqueue time stamps, we most definitely can't enqueue span relationships. Similarly, Scope API and lifecycles cannot be ensured. The bottom line is: This introduces a lot of ambiguity, to the point where it gets impossible to predict SDK behaviour.
All three solutions have a common issue: They increase bundle size of the deliberately minimal, eagerly loaded loader script. Something we want to explicitly avoid.
What can we do? We can export something like a LoaderSentry type from our NPM packages that accurately represents the "safe" callable APIs for anyone using typescript (i.e. a loader-based setup that also installs @sentry/* packages for at least typing). This way, users have at least certainty over which types can be used. Obviously, it requires typescript. The loader is often used in scenarios where people just want to plug Sentry into their website without having an NPM-based setup (think wordpress, some statically server-rendered pages, etc).
Thanks for explaining the trade-offs. I'd be interested in working on the TypeScript-only approach you suggested, rather than changing the loader's runtime behavior.
I'd start by checking the existing loader API and the SDK packages' type exports, then look at how to expose a LoaderSentry type that reflects the APIs safely callable before the full bundle loads.
Would that be a useful contribution to take forward?
@faizansaiyed123 yes, your approach sounds reasonable. Feel free to go ahead with the PR! If it works well, and has no drawbacks, I'm happy to merge it.
Activity
linear-code commentedon Jun 25, 2026
JS-2871
Lms24 commentedon Jun 26, 2026
We talked a bit about this and unfortunately, all of the suggested solutions have drawbacks that make it unlikely for us to implement them. That being said, there's at least a bit of typing help we can add for TS-based setups that still use the loader.
Let me explain our thoughts on the options:
addIntegrationis a widely-used API for loader users.Sentrycalls anymore. Yes they don't error but nevertheless, they have no effect. I agree that this fulfills the "fail silently" criterion for SDKs, so we can think about it, but it won't solve any legitimate issue for SDK users expecting SDK behaviour (for example when callingSentry.addIntegration)captureExceptionfunction returns no event id, while the actualcaptureExceptionreturns said id. Another issue are all timing-sensitive APIs.Sentry.start*Span*or logger and metric APIs being the prime example. While we can enqueue time stamps, we most definitely can't enqueue span relationships. Similarly, Scope API and lifecycles cannot be ensured. The bottom line is: This introduces a lot of ambiguity, to the point where it gets impossible to predict SDK behaviour.All three solutions have a common issue: They increase bundle size of the deliberately minimal, eagerly loaded loader script. Something we want to explicitly avoid.
What can we do? We can export something like a
LoaderSentrytype from our NPM packages that accurately represents the "safe" callable APIs for anyone using typescript (i.e. a loader-based setup that also installs@sentry/*packages for at least typing). This way, users have at least certainty over which types can be used. Obviously, it requires typescript. The loader is often used in scenarios where people just want to plug Sentry into their website without having an NPM-based setup (think wordpress, some statically server-rendered pages, etc).faizansaiyed123 commentedon Oct 13, 2026
Thanks for explaining the trade-offs. I'd be interested in working on the TypeScript-only approach you suggested, rather than changing the loader's runtime behavior.
I'd start by checking the existing loader API and the SDK packages' type exports, then look at how to expose a
LoaderSentrytype that reflects the APIs safely callable before the full bundle loads.Would that be a useful contribution to take forward?
Lms24 commentedon Oct 13, 2026
@faizansaiyed123 yes, your approach sounds reasonable. Feel free to go ahead with the PR! If it works well, and has no drawbacks, I'm happy to merge it.
ref(browser): Use named type imports for LoaderSentry
docs(browser): Show full SDK cast inside onLoad in LoaderSentry example
ref(browser): Use named type imports for LoaderSentry
docs(browser): Show full SDK cast inside onLoad in LoaderSentry example