Skip to content

Loader stub silently drops calls outside queued method list, which results in either silent no-ops #21806

Closed

Description

@ndmanvar

Problem Statement

Problem

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

  1. 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
  2. Catch-all no-op proxy — intercept any unrecognized property access pre-load and return a no-op function; prevents crashes but silently swallows calls
  3. 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.

Additional Context

References

  • Loader stub source: packages/browser-integration-tests/fixtures/loader.js
  • addIntegration implementation: packages/core/src/integration.ts

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.

Activity

  1. moved this to Waiting for: Product Owner in GitHub Issues with 👀 3on Jun 25, 2026
  2. linear-code commented on Jun 25, 2026

    @linear-code
  3. Lms24 commented on Jun 26, 2026

    @Lms24
    Member

    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:

    1. 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.
    2. 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)
    3. 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).

  4. moved this from Waiting for: Product Owner to No status in GitHub Issues with 👀 3on Jun 26, 2026
  5. faizansaiyed123 commented on Oct 13, 2026

    @faizansaiyed123
    Contributor

    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?

  6. moved this to Waiting for: Product Owner in GitHub Issues with 👀 3on Oct 13, 2026
  7. Lms24 commented on Oct 13, 2026

    @Lms24
    Member

    @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.

  8. moved this from Waiting for: Product Owner to No status in GitHub Issues with 👀 3on Oct 13, 2026
  9. linked a pull request that will close this issuefeat(browser): add LoaderSentry type #25357on Oct 16, 2026
  10. self-assigned this
    on Oct 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions