The popular duration-biased before_send_transaction pattern (keep 100% of >=5s, 50% of 2-5s, 10% of 1-2s, ~base rate below — Neil Kakkar's widely-copied Sentry duration-span-sampling recipe) interacts badly with route exclusions if the exclusion only LOWERS the base sample rate instead of returning None. The duration ladder's if duration >= 5: return event runs after the exclusion check and keeps every slow request on the 'excluded' route anyway.
for utility_route in utility_routes:
if utility_route in url_string:
default_sample_rate = 0.0001 # BROKEN: ladder below still keeps >=5s
# fix: return None here instead
if duration_seconds >= 5:
return event # re-admits the excluded routeWhere this bites hardest: a Sentry tunnel/proxy endpoint (the standard tunnel pattern for ad-blocker bypass). Tunnel requests are slow exactly when Sentry ingest or the network is slow, so they reliably cross the 5s keep-all threshold. Observed in a FastAPI prod app over 30d: the tunnel endpoint was the #2 transaction by total duration (18,665s, p50 10.3s among kept samples) and the tunnel handler was the #1 function by profile self-time (6,962s) — the observability pipeline dominating its own telemetry, with transaction-based profiling attaching profiles to those kept transactions and skewing all function metrics.
Fix: route exclusions in before_send_transaction must return None immediately, before any duration logic. Audit rule: any exclusion implemented as 'set a very low rate' inside a function that also has an unconditional duration keep is broken.