Troubleshooting
Monitoring & logging

Fix Sentry Not Receiving Errors From Django in Production

Fix Sentry showing no events from a production Django app: check the DSN and environment, initialize sentry-sdk early in settings, make sure Celery and Gunicorn workers initialize too, and look for sampling, filters, rate limits, and blocked outbound traffic.

Problem statement

Users report 500 errors, the logs show tracebacks, but the Sentry project is empty, or it receives errors from the web app and nothing from Celery. Sentry fails quietly by design: if the SDK is not initialized, has no DSN, cannot reach Sentry, or decides to drop an event, your app keeps running and nothing tells you. You have to check each link in the chain.

Where events get lostException raisedin view or taskSDK initialized?DSN, processEvent filtered?sample, before_sendSent to Sentrynetwork, quotaSentry drops events silently, so verify each step from init to delivery.
  1. Send a test from the server: python manage.py shell -c "import sentry_sdk; sentry_sdk.capture_message('test'); sentry_sdk.flush()".
  2. Check the DSN is set in production: an empty DSN disables the SDK without error.
  3. Call sentry_sdk.init() in settings, so every process that loads Django initializes it, including Celery workers.
  4. Look for sample_rate, before_send, or ignore_errors settings dropping events.
  5. Check the project's Stats page for dropped events (rate limits, spike protection, quota).

Step-by-step solution

1. Send a test event

python manage.py shell -c "
import sentry_sdk
print('client active:', sentry_sdk.get_client().is_active())
sentry_sdk.capture_message('sentry test from production')
sentry_sdk.flush(timeout=5)
"

If is_active() is False, the SDK never initialized with a DSN in this process. If it is True and nothing arrives, the event was dropped or blocked on the way.

2. Initialize in settings with the DSN

# settings/production.py
import sentry_sdk

SENTRY_DSN = os.environ.get("SENTRY_DSN", "")
if SENTRY_DSN:
    sentry_sdk.init(
        dsn=SENTRY_DSN,
        environment=os.environ.get("SENTRY_ENVIRONMENT", "production"),
        release=os.environ.get("GIT_SHA"),
        send_default_pii=False,
        traces_sample_rate=0.1,
    )

The Django integration is enabled automatically when Django is installed. Putting init() in settings means Gunicorn workers, management commands, and Celery all initialize it, because they all load settings. Initializing in wsgi.py only covers the web process.

where the event stoppedWhat you findCause and fixclient not activeempty DSN or no init; init in settingsweb works, Celery silentinit only in wsgi.py; move to settingstest arrives, errors do notbefore_send or ignore_errors; reviewStats shows droppedquota or rate limit; adjust samplingEach step can drop events without any error in your appdjango-deployment.com
The test message in step one tells you which half of the chain to inspect.

3. Check filters and sampling

sentry_sdk.init(
    dsn=SENTRY_DSN,
    sample_rate=1.0,          # errors: keep at 1.0
    traces_sample_rate=0.1,   # performance only
    before_send=drop_noise,
)

sample_rate below 1.0 drops a share of error events. traces_sample_rate affects only performance data, not errors. A before_send hook that returns None too broadly, or an ignore_errors list with a base class like Exception, hides everything. Errors that Django handles itself, such as Http404 and PermissionDenied, are not reported by design.

4. Make sure errors are not swallowed

If your code catches exceptions and returns a response, Sentry never sees them. Report them explicitly:

try:
    sync_order(order)
except ExternalAPIError:
    sentry_sdk.capture_exception()
    return JsonResponse({"error": "sync failed"}, status=502)

Logged errors are captured too: the logging integration sends logger.error() records as events by default.

5. Check delivery

From the server, confirm outbound HTTPS to Sentry works:

curl -sS -o /dev/null -w "%{http_code}\n" https://o123456.ingest.sentry.io/api/123/envelope/

Any HTTP status (often 400 or 405 without a body) proves connectivity; a timeout means a firewall or egress rule blocks it. Then check the Sentry project's Stats page: events dropped by rate limits, spike protection, or an exhausted quota appear there, not in your app.

coverage by init locationinit in wsgi.pyinit in settingsGunicorn workersyesyesCelery workers!noyesCelery beat!noyesmanage.py, cron!noyesSettings are loaded by every process; wsgi.py only by the web serverdjango-deployment.com
Tag each process with its own server_name or a tag so you can filter by source.

Explanation

The Sentry SDK hooks into Django's request handling and Python's logging, builds an event for each unhandled exception, applies sampling and your filters, and sends it from a background thread. Every step is designed to never break the app: a missing DSN disables the SDK, network errors are swallowed, and dropped events are counted on the server side. That makes Sentry safe to run and easy to misconfigure without noticing.

Edge cases / notes

  • Short-lived processes. Cron commands that exit immediately can quit before the background thread sends; call sentry_sdk.flush() at the end.
  • Forking. Initializing before Gunicorn forks (with preload_app) is supported, but initializing in a post-fork hook is safer for some transports.
  • Self-hosted. For self-hosted Sentry or GlitchTip, the DSN host must be reachable from production networks, not just your office.

Next steps

FAQ

Why does Sentry not report 404 errors?

Django handles Http404 itself and returns a response, so the SDK does not treat it as an error. That is intended.

Does traces_sample_rate affect errors?

No. It controls performance traces. Error sampling is sample_rate, which should usually stay at 1.0.

Why do Celery task errors not show up?

Sentry was probably initialized only in wsgi.py. Initialize it in settings so workers load it too.

How do I know if events are being dropped by quota?

Open the project's Stats page in Sentry. It shows accepted, filtered, and dropped events with reasons.

Keep going