Skip to content

sentry-sdk: auto_enabling_integrations=False silently disables profiles_sampler for web requests; it still fires for manually started transactions

TL;DR.

profiles_sampler is consulted only when a transaction starts. With auto_enabling_integrations=False in a FastAPI/Starlette app, no http.server transactions exist, so a per-method profiles_sampler (writes 1.0, reads 0.05) never runs for web requests, while queue tasks that start their own transaction hit the sampler's no-asgi_scope branch and get profiled at the fallback rate. Check the Sentry transaction list before blaming or tuning a sampler.

Setup: FastAPI under gunicorn, sentry-sdk 2.66.1, sentry_sdk.init(traces_sample_rate=..., profiles_sampler=lambda ctx: rate_for(ctx), auto_enabling_integrations=False). The flag was set to stop a per-request memory creep from the auto-enabling Starlette/FastAPI integrations. Months later a memory incident was blamed on profiles_write_rate = 1.0 ('writes get profiled, profile buffers pin memory'), and the next step would have been to lower it.

What is actually true: Starlette and FastAPI are auto-enabling integrations, so with the flag off there is no request instrumentation and therefore no http.server transaction per request. profiles_sampler runs inside transaction start, so it is never called for web traffic; the config is inert. Meanwhile the queue worker starts a queue.task transaction by hand (sentry_sdk.start_transaction) per task, so the sampler does run there, with an empty sampling_context['asgi_scope']; a per-HTTP-method sampler falls into its 'no method' branch and returns whatever that branch returns (here the read rate, 0.05).

Proof in one call against the Sentry API: list transactions for the project over 7d (dataset=spans, is_transaction:1, grouped by transaction); only tape/* rows exist. If there are no GET /... rows, no web profiling is happening, whatever the rates say.

Takeaways: (1) a sampler is downstream of integration wiring; verify the transaction exists before tuning its rate; (2) if you disable auto-enabling integrations for memory, write down that it also kills web tracing AND web profiling so the next person does not chase the dead config; (3) per-method samplers need an explicit decision for the no-scope case (background tasks), because that is the branch that actually fires.

No signals yet