Skip to content

thirdPartyErrorFilterIntegration does not filter errors correctly #13835

Closed

Description

@gabrielecirulli

Is there an existing issue for this?

How do you use Sentry?

Sentry Saas (sentry.io)

Which SDK are you using?

@sentry/browser

SDK Version

8.32.0

Framework Version

Svelte 4.2.19

Link to Sentry event

https://2048-ip-holding-bv.sentry.io/issues/7739542/?project=4507408148856912&query=is%3Aunresolved%20issue.priority%3A%5Bhigh%2C%20medium%5D&referrer=issue-stream&statsPeriod=24h&stream_index=7

Reproduction Example/SDK Setup

No response

Steps to Reproduce

Reproduction is difficult because the issue stems from third-party ad code injected by the Ezoic Standalone SDK. The quality and error rate are unpredictable during user sessions, and we have no control over when the errors occur since the code is injected by third parties.

However, the problem should be visible through the provided event link in Sentry. If you look at the stack trace you'll notice that:

  • All except 1 of the stack frames are from a script /ym.0.js. This is a third-party script
  • The bottom stack frame is considered part of my node_modules: node_modules/.pnpm/@sentry+browser@8.32.0/node_modules/@sentry/browser/build/npm/esm/helpers.js

My thirdPartyErrorFilterIntegration is set to "drop-error-if-exclusively-contains-third-party-frames" and it should be dropping these errors completely, but I believe it doesn't due to that one stack frame at the bottom.

This is thoroughly overwhelming my quotas: within 24 hours I've blown through the 50k errors in my account and I'm at a loss for how to continue. I've switched the mode to "drop-error-if-contains-third-party-frames" for now but this will kill my visibility on errors that are partially related to my code. It is ok as a temporary measure, but I need a long-term fix.


Here is a description of my setup:

  • Vite TypeScript app.
  • Using Svelte as a front-end framework
  • Svelte is initialized by importing the SDK into my bundled code and with the following config:
// This module is a convenience to ensure config across main and worker initializations
import { init, thirdPartyErrorFilterIntegration } from "@sentry/svelte";

declare global {
  const SENTRY_FINGERPRINT_FOR_FILTERING_OUT_ERRORS_FROM_THIRD_PARTY_CODE: string;
}

init({
  dsn: "<snip>",
  maxBreadcrumbs: 200,
  integrations: [
    thirdPartyErrorFilterIntegration({
      filterKeys: [SENTRY_FINGERPRINT_FOR_FILTERING_OUT_ERRORS_FROM_THIRD_PARTY_CODE],
      behaviour: "drop-error-if-contains-third-party-frames",
    }),
  ],
});

Then, the Sentry fingerprint is set up as follows in vite.config.ts (this snippet is heavily altered to avoid listing the other plugins):

import { sentryVitePlugin } from '@sentry/vite-plugin';
import { defineConfig, loadEnv } from 'vite';

const SENTRY_FINGERPRINT_FOR_FILTERING_OUT_ERRORS_FROM_THIRD_PARTY_CODE =
  '<my_key_here>';

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    // ... Other unrelated plugins ...

    // Last plugin
    sentryVitePlugin({
      applicationKey:
        SENTRY_FINGERPRINT_FOR_FILTERING_OUT_ERRORS_FROM_THIRD_PARTY_CODE,
      org: '<snip>',
      project: '<snip>',
    }),
  ],
  define: {
    SENTRY_FINGERPRINT_FOR_FILTERING_OUT_ERRORS_FROM_THIRD_PARTY_CODE:
      JSON.stringify(
        SENTRY_FINGERPRINT_FOR_FILTERING_OUT_ERRORS_FROM_THIRD_PARTY_CODE
      ),
  },
});

Just to be sure, I also verified that my bundled code also contains the following bits of JS that should be identifying the modules. Notice how the app key is in there:

!(function () {
  try {
    var e =
        "undefined" != typeof window
          ? window
          : "undefined" != typeof global
            ? global
            : "undefined" != typeof self
              ? self
              : {},
      t = new e.Error().stack;
    t &&
      ((e._sentryDebugIds = e._sentryDebugIds || {}),
      (e._sentryDebugIds[t] = "<snip>"),
      (e._sentryDebugIdIdentifier = "<snip>"));
  } catch (i) {}
})();
var e =
  "undefined" != typeof window
    ? window
    : "undefined" != typeof global
      ? global
      : "undefined" != typeof self
        ? self
        : {};
(e._sentryModuleMetadata = e._sentryModuleMetadata || {}),
  (e._sentryModuleMetadata[new e.Error().stack] = Object.assign(
    {},
    e._sentryModuleMetadata[new e.Error().stack],
    { "_sentryBundlerPluginAppKey:<my_key_here>": !0 },
  ));

Dependencies:

  • svelte 4.2.19
  • @sentry/svelte 8.32.0
  • @sentry/vite-plugin 2.22.4
  • @sveltejs/vite-plugin-svelte 3.0.2
  • typescript 5.6.2
  • vite 5.4.8

...and a couple more

Expected Result

Errors such as the one linked, and many more in my dashboard, should have been discarded clientside, but somehow the snippet shown in the bottom stack frame, presumably causes them to be included (I say presumably because I don't know for sure this is the case but I presume so from reading the source of thirdPartyErrorFilterIntegration)

Here's the relevant snippet being included in the stack trace, from file node_modules/.pnpm/@sentry+browser@8.32.0/node_modules/@sentry/browser/build/npm/esm/helpers.js

      // Attempt to invoke user-land function
      // NOTE: If you are a Sentry user, and you are seeing this stack frame, it
      //       means the sentry.javascript SDK caught an error invoking your application code. This
      //       is expected behavior and NOT indicative of a bug with sentry.javascript.
      return fn.apply(this, wrappedArguments);

Here's a link to the file in question in this repo.

I don't know why this function is part of the stack trace.

Actual Result

Errors that should be filtered according to "drop-error-if-exclusively-contains-third-party-frames" are not filtered, overwhelming my quota. About 40k of the 50k errors I've received in the last 24 hours should have been dropped. It seems like a single stack frame is preventing them from being dropped.

You can review the following samples. Please note how the last stack frame always originates from some Sentry code and is presumably blocking the event from being dropped.

Activity

  1. moved this to Waiting for: Product Owner in GitHub Issues with 👀 3on Sep 30, 2024
  2. lforst commented on Oct 1, 2024

    @lforst
    Contributor

    Hi, since you said you set the behaviour to "drop-error-if-exclusively-contains-third-party-frames", and there is a frame from your own code in the stack frame, the event should not be dropped and everything is behaving as designed.

    In this case, since the third-party script path doesn't seem to change you can use the denyUrls option: https://docs.sentry.io/platforms/javascript/configuration/filtering/#using-allowurls-and-denyurls

    Maybe with something like denyUrls: [/\/ym\.1\.js$/, /\/ym\.2\.js$/]

  3. moved this from Waiting for: Product Owner to No status in GitHub Issues with 👀 3on Oct 1, 2024
  4. gabrielecirulli commented on Oct 1, 2024

    @gabrielecirulli
    Author

    @lforst You're right that there's a frame from my code in the samples, but this frame is auto-injected by the Sentry SDK outside my control and it breaks the expectation of how "drop-error-if-contains-third-party-frames" should work.

    I can't control the presence of this frame as it is injected automatically, nor can I easily instruct the SDK to ignore it. As a result, any error from third-party code will include this frame if it interacts with the instrumentation. To me, this looks like a design flaw in the SDK or in "drop-error-if-contains-third-party-frames" as it does not behave as implied in its name for unpredictable reasons outside my control.

    Yes, from a technical perspective the frame in question is from my code, but I have no control over it being there, and all of the errors I linked should have been dropped when following the intended behavior of "drop-error-if-contains-third-party-frames".

    Your suggestion of using denyUrls would not work for me, because the scripts change constantly and are dependent on the current ads on the page.

    I also want "drop-error-if-contains-third-party-frames" to correctly identify errors in third-party scripts that originate from an action I took in my code, such as interacting with the ad network's SDK. Therefore plainly denying all external URLs would also not work.

    This seems like a significant issue for any Sentry customer running ads, as it undermines trust in "drop-error-if-contains-third-party-frames". It also has serious financial or service implications, as in my case, where it caused me to exceed my monthly quota in a single day, leaving me without error observability for the rest of the month.

  5. moved this to Waiting for: Product Owner in GitHub Issues with 👀 3on Oct 1, 2024
  6. lforst commented on Oct 1, 2024

    @lforst
    Contributor

    From my point of view, this works as expected. The integration does as much as is technically possible. The SDK is part of your code (i.e. code you included into your bundles), and you likely wouldn't wanna throw away events if the SDK is causing bugs.

    As you have already correctly identified, if you really want to get rid of these events automatically, you can set "drop-error-if-contains-third-party-frames".

    You have all the possibilities beforeSend, which you can use to drop events at will. I came up with and built the thirdPartyErrorFilterIntegration and I can tell you there is nothing more I can think of we could do. If you have a suggestion, please let us know!

  7. moved this from Waiting for: Product Owner to No status in GitHub Issues with 👀 3on Oct 1, 2024
  8. gabrielecirulli commented on Oct 1, 2024

    @gabrielecirulli
    Author

    @lforst I agree with you that, from a technical standpoint, the integration functions as expected, and I understand that events from the SDK shouldn't be discarded outright.

    However, this setup makes it very difficult for me to filter out errors caused by third-party code where I am neither the source nor the caller. How are your other clients handling this, particularly those with ad-heavy sites? I would be surprised if I'm the only one facing this challenge.

    As mentioned earlier, this issue has significant business implications for me. My options seem to be very limited:

    • Discard all events that include third-party code, even in cases where I am the caller (these sorts of errors currently exist and I am unable to track them or I'd go over my quota).
    • Build my own filtering system, though I'm unsure where to begin. If thirdPartyErrorFilterIntegration is unable to offer this functionality given you've built the SDK, I'm not confident I could develop a better solution. I don't have the insight for it.
    • Opt out of the bundled Sentry JS SDK entirely?

    None of these options is satisfactory.

    Looking again at the code in the stack trace, it appears to be glue code. Even the comment indicates this code isn't meant to be treated as part of the stack trace, but rather that an error occurred downstream after Sentry wrapped global objects with its own handlers:

          // Attempt to invoke user-land function
          // NOTE: If you are a Sentry user, and you are seeing this stack frame, it
          //       means the sentry.javascript SDK caught an error invoking your application code. This
          //       is expected behavior and NOT indicative of a bug with sentry.javascript.
          return fn.apply(this, wrappedArguments);
    

    I feel that no viable solution is being proposed here. I only have a choice between missing critical errors related to third-party code or severely exceeding my budget and quota by letting too many unnecessary event through the filter over a technicality.

    I would agree with your position if the code in the stack trace was unrelated, but it’s directly tied to the core functionality of the Sentry SDK. This piece of code causes another part of your SDK not to work as intended. You're right, the respective units of code work exactly as intended. The interaction between them is a bug with serious ramifications.

  9. 42 remaining items

  10. gabrielecirulli commented on Dec 5, 2025

    @gabrielecirulli
    Author

    Hi @chargome, thank you for your message! Yes, that would be a perfect solution in my opinion. As long as it's a fully-opt in option that advertises the potential tradeoffs, I think it would work.

    Maybe a heuristic like this?

    • All frames except the last belong to external scripts
    • The last frame is explicitly from the Sentry file in question (and maybe ideally matched strictly to the line of the above code snippet containing fn.apply(this, wrappedArguments) somehow, to avoid false positives?)

    Reading back on the comment by @lforst, potentially you could include a "tagging string" (i.e. a unique string in the code, next to the line that ends up in the stack trace) that would aid in matching and be unaffected by minification?

  11. moved this to Waiting for: Product Owner in GitHub Issues with 👀 3on Dec 5, 2025
  12. chargome commented on Dec 5, 2025

    @chargome
    Member

    Reading back on the comment by lforst, potentially you could include a "tagging string" (i.e. a unique string in the code, next to the line that ends up in the stack trace) that would aid in matching and be unaffected by minification?

    Potentially, will have a look at the implementation details next week then. You'll be notified in this issue once we have something working 👍

  13. self-assigned this
    on Dec 5, 2025
  14. moved this from Waiting for: Product Owner to No status in GitHub Issues with 👀 3on Dec 5, 2025
  15. chargome commented on Dec 30, 2025

    @chargome
    Member

    @gabrielecirulli You'll be notified in this issue once this gets released (likely next week). We settled on a new opt-in option ignoreSentryInternalFrames for this integration that should do the job.

  16. lforst commented on Dec 31, 2025

    @lforst
    Contributor

    @chargome mayyybe I would recommend putting a note somewhere - jsdoc or whatever - that the new option will not work in the browser, which I have to admit, is a bit unfortunate because the integration was primarily designed for the browser where you get errors from browser extensions and stuff.

  17. github-actions commented on Jan 12, 2026

    @github-actions
    Contributor

    A PR closing this issue has just been released 🚀

    This issue was referenced by PR #18632, which was included in the 10.33.0 release.

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