#4998·civitai

faro: extension-injected frames still classify as real app errors (follow-up to #4994)

Author: ZacxDevCreated Sep 21, 2026Updated Sep 21, 2026

Follow-up to #4994, which fixed three of the four ways a third-party Failed to fetch was reaching the real (app-bug) class in the Faro exception classifier.

The remaining case

hasProjectSourceFrame in src/utils/faro/classifyException.ts treats a browser-extension-injected frame as project source, so an exception originating entirely in an extension still classifies as real.

It is the whole class, not one browser — chrome-extension://, moz-extension:// and safari-web-extension:// all reach the bare-extension test the same way. A fix scoped to one scheme would leave the other two.

Size

Measured over ~1,000 live RUM beacons at the time #4994 was prepared: 314 / 957 (32.8%) of the context_error_category="real" population carried an extension-injected frame — roughly 2.1× the share #4994 itself removed. So this is the larger remaining contaminant.

Why it was deferred rather than folded into #4994

The natural fix routes through isInjectedFrame, which drives a DROP decision. Widening it therefore widens a drop path, and the classifier's stated safety posture is a conservative allowlist: anything unmatched falls through to real and is kept, because a false drop hides a real bug. That change deserves its own evidence and its own review rather than riding along with an unrelated fix.

Closing condition

A PR handling all three injected-extension schemes (chrome-extension://, moz-extension://, safari-web-extension://), graded by re-running the same beacon replay used for #4994 and showing the drop rate move.

Checked by: that PR merging to main with the before/after drop-rate measurement posted in its body.

Notes for whoever picks this up

  • Keep the fail-open posture: prefer tagging over dropping if the evidence is ambiguous, so nothing is hidden from the data even when it is excluded from the actionable class.
  • #4994 added a regression guard worth preserving: @trpc/client dispatches from a setTimeout, so a genuine first-party API failure carries no app frame and is kept only by an explicit API-client allowlist. Any widening of the injected-frame logic should be checked against that case — 183/957 (19.1%) of the population depended on it.
  • The test file is src/utils/faro/__tests__/classifyException.test.ts; #4994's cases show the fixture shape, including realistic multi-frame stacks.