From f228e6c72a9108a1caa121d54d5bbe991b439bf7 Mon Sep 17 00:00:00 2001 From: Lucas Braum Date: Sat, 17 Oct 2026 10:15:55 -0700 Subject: [PATCH] fix(packs): leave beforeSendTransaction alone where traceLifecycle is set (UPT-88) The Sentry 10 to 11 rules for beforeSendTransaction and ignoreTransactions reported every init that sets them. Both only stop working under span streaming, and traceLifecycle keeps transactions, so an init that sets it is not a site. Found as a breaking false positive in the @sentry/react ground truth (BotFleet). Co-Authored-By: Claude Sonnet 5.5 Signed-off-by: Lucas Braum --- .changeset/sentry-trace-lifecycle-static.md | 5 +++++ packages/core/src/packs/sentry/detect.ts | 15 ++++++++++++--- packages/core/src/packs/sentry/rules.ts | 4 ++-- packages/core/src/packs/sentry/sentry.test.ts | 14 ++++++++++++++ 4 files changed, 33 insertions(+), 5 deletions(-) create mode 100644 .changeset/sentry-trace-lifecycle-static.md diff --git a/.changeset/sentry-trace-lifecycle-static.md b/.changeset/sentry-trace-lifecycle-static.md new file mode 100644 index 0000000..36159d4 --- /dev/null +++ b/.changeset/sentry-trace-lifecycle-static.md @@ -0,0 +1,5 @@ +--- +'uptide': patch +--- + +The Sentry 10 to 11 pack no longer reports `beforeSendTransaction` or `ignoreTransactions` in a `Sentry.init` that sets `traceLifecycle`: the option keeps transactions, so they still work. diff --git a/packages/core/src/packs/sentry/detect.ts b/packages/core/src/packs/sentry/detect.ts index 20066b2..e5abe22 100644 --- a/packages/core/src/packs/sentry/detect.ts +++ b/packages/core/src/packs/sentry/detect.ts @@ -29,10 +29,19 @@ import { const SOURCE = /\.[cm]?[jt]sx?$/; const NEXT_CONFIG = /(?:^|\/)next\.config\.(?:js|mjs|cjs|ts|mts)$/; -/** `Sentry.init` option paths found in a file, as sites. */ -export function initOptionSites(paths: readonly string[]) { +/** + * `Sentry.init` option paths found in a file, as sites. `unless` names options of the same + * object that keep the path working (`traceLifecycle` keeps `beforeSendTransaction`): an object + * that sets one is not reported. + */ +export function initOptionSites(paths: readonly string[], unless: readonly string[] = []) { return (text: string, file: string): SourceSite[] => - SOURCE.test(file) ? propertySites(initOptions(parse(text, file)), paths) : []; + SOURCE.test(file) + ? propertySites( + initOptions(parse(text, file)).filter((o) => !unless.some((key) => propertyAt(o, key))), + paths, + ) + : []; } /** Option paths of the named integrations' options objects. */ diff --git a/packages/core/src/packs/sentry/rules.ts b/packages/core/src/packs/sentry/rules.ts index a027bec..a3a15e0 100644 --- a/packages/core/src/packs/sentry/rules.ts +++ b/packages/core/src/packs/sentry/rules.ts @@ -205,7 +205,7 @@ export const SENTRY_RULES: readonly SentryRule[] = [ kinds: [...INIT_KINDS], symbols: symbols(['ignoreTransactions']), message: named(['ignoreTransactions']), - detect: initOptionSites(['ignoreTransactions']), + detect: initOptionSites(['ignoreTransactions'], ['traceLifecycle']), guide: `ignoreTransactions still compiles (deprecated) but does nothing with span streaming (${anchor('replacing-ignoretransactions-with-ignorespans')}). Options: (a) ignoreSpans with the same patterns — it matches every span, not only the root, so prefer the object form { name, attributes: { 'sentry.op': ... } } where a child span could share the name; (b) traceLifecycle: 'static' to keep transactions (temporary: planned for removal). Span names are low-cardinality in v11 and ignoreSpans runs at span start: a pattern matching a raw URL or SQL text may need to match url.path or db.query.text instead. ${CHOOSE}`, }, { @@ -216,7 +216,7 @@ export const SENTRY_RULES: readonly SentryRule[] = [ kinds: [...INIT_KINDS], symbols: symbols(['beforeSendTransaction']), message: named(['beforeSendTransaction']), - detect: initOptionSites(['beforeSendTransaction']), + detect: initOptionSites(['beforeSendTransaction'], ['traceLifecycle']), guide: `beforeSendTransaction still compiles (deprecated) but no transaction events exist with span streaming (${anchor('replacing-beforesendtransaction')}). Options: (a) move scrubbing to beforeSendSpan guarded by span.is_segment, and dropping to ignoreSpans (beforeSendSpan cannot drop); (b) traceLifecycle: 'static' to keep transactions. Scope tags and extra no longer reach spans: use setAttribute(s). ${CHOOSE}`, }, { diff --git a/packages/core/src/packs/sentry/sentry.test.ts b/packages/core/src/packs/sentry/sentry.test.ts index 1edb8ba..5ed8686 100644 --- a/packages/core/src/packs/sentry/sentry.test.ts +++ b/packages/core/src/packs/sentry/sentry.test.ts @@ -147,6 +147,20 @@ describe('compiler-blind detection', () => { ]); }); + it("keeps beforeSendTransaction and ignoreTransactions where traceLifecycle: 'static' is set", () => { + const init = (extra: string) => + [ + "import * as Sentry from '@sentry/browser';", + `Sentry.init({ ${extra}beforeSendTransaction: (e) => e, ignoreTransactions: ['x'] });`, + '', + ].join('\n'); + expect(sites(sentryBrowserPack, 'sentry.ts', init(''))).toEqual([ + 'ignore-transactions:2', + 'before-send-transaction:2', + ]); + expect(sites(sentryBrowserPack, 'sentry.ts', init("traceLifecycle: 'static', "))).toEqual([]); + }); + it('ignores the same reads on objects that are not Sentry spans', () => { const text = [ "import * as Sentry from '@sentry/browser';",