Skip to main content

Sentry Error Tracking: Catch Bugs Before Your Users Do

Updated 8 min readMarkdown

Quick answer

Sentry error tracking collects the exceptions your Python app raises in production and groups them into issues you can triage, with the stack trace and how many users were hit. Install sentry-sdk, call sentry_sdk.init() with your project DSN as early as possible, and every unhandled exception is reported automatically. It is worth it once real users can hit errors you never see in development.

Your checkout worked on your laptop. It passed review, the tests were green, and the deploy went out on a Friday afternoon. Then a customer writes on Monday that their order failed, and you have nothing to go on. No log line, no stack trace, just a screenshot and a vague description. You open the logs and find a wall of lines, most harmless, while the one line that matters sits buried in the middle. That gap, between an error happening and your team knowing about it, is the whole problem. Sentry closes it by catching the exception the moment it happens and sending you the details.

What I would check before using it

My first check is whether real users can reach the code. If the app only runs on your own machine, a traceback in the terminal is enough and Sentry adds nothing. Once strangers can trigger a crash, you need to know about it before they tell you.

My second check is error volume against the free tier. Sentry gives you a monthly event allowance, and one noisy loop raising the same exception hourly will eat it in a day. Before I would switch it on, I want alert rules that group repeats instead of paging me for each one.

My third check is what data leaves my server. An event carries the stack trace, and it can also carry request data and local variables. If the app handles passwords or payment details, I want to test how Sentry scrubs them with a deliberately bad event first.

My fourth check is framework support. The Python SDK plugs into Django, Flask, and FastAPI with almost no extra code. A small Flask service needs the same two steps as anything else: install the SDK and call init early. The same init-first rule applies on the Node side, as the Express post shows.

My verdict, as judgement: adopt Sentry error tracking when the app is in production, real users can trigger errors, and someone owns the triage. Skip it for a weekend project or a script you run by hand. The recommendation flips the moment error volume outruns the budget, or sensitive data cannot be scrubbed cleanly, in which case self-hosted logging is the better trade.

One order total, run end to end

The example is a small shop checkout: three items with a name, a price in rupees, and a quantity. The order_total function adds up price times quantity. Two items are fine. The third, a laptop stand, has no price at all, because the catalogue entry was saved before anyone filled that field in. That is the kind of bad data that passes every hand-built test cart, then breaks the first real order.

import sentry_sdk

cart = [ {"name": "Mechanical keyboard", "price": 18500, "qty": 1}, {"name": "USB-C hub", "price": 6400, "qty": 2}, {"name": "Laptop stand", "qty": 1}, ]

def order_total(items): total = 0 for item in items: total += item["price"] * item["qty"] return total

captured = []

def record(event, hint): captured.append(event) return event

The script runs the same cart twice: once before Sentry is initialised, the mistake I wanted to show, and once after sentry_sdk.init(), with a before_send hook saving every event into a list. I used a placeholder DSN, so nothing reached a dashboard.

print("Phase 1: crash before Sentry is initialised")
try:
    print("Total:", order_total(cart))
except KeyError as exc:
    print("KeyError:", exc)
print("Events captured so far:", len(captured))

print("Phase 2: Sentry initialised, running the same cart again") sentry_sdk.init( dsn="https://examplePublicKey@o0.ingest.sentry.io/0", before_send=record, ) try: print("Total:", order_total(cart)) except KeyError: sentry_sdk.capture_exception() print("Caught the KeyError and handed it to Sentry.") sentry_sdk.flush() print("Events captured:", len(captured)) if captured: exc = captured[0]["exception"]["values"][0] print("Captured event:", exc["type"], exc["value"])

Here is the real output from the run:

Phase 1: crash before Sentry is initialised
KeyError: 'price'
Events captured so far: 0
Phase 2: Sentry initialised, running the same cart again
Caught the KeyError and handed it to Sentry.
Events captured: 1
Captured event: KeyError 'price'
Sentry is attempting to send 1 pending events
Waiting up to 2 seconds
Press Ctrl-C to quit

The thing that went wrong is in phase 1: the cart crashed with KeyError: 'price', and zero events were captured, because Sentry had not been initialised yet. An SDK cannot report an error from before it existed. The fix is ordering, not configuration: call sentry_sdk.init() at the very top of your entry point, before any app code runs. In phase 2, the same crash produced exactly one captured event, the exception type and value printed from the list. The last three lines are the SDK flushing on exit. The data needs a fix too: adding the missing price of 9200 makes the fixed cart total 40500. Better still, validate incoming records first, so a missing field fails at the door. My post on Pydantic shows how that validation looks in practice.

Common mistakes and how to fix them

First, initialising Sentry too late. The symptom is silence: crashes happen, users complain, and the Sentry dashboard shows nothing. The fix is to call sentry_sdk.init() at the top of your entry point, before imports that run app code, before the server starts listening, and before any background thread starts work.

Second, swallowing exceptions with a bare except. The symptom is a function that returns None or an empty page instead of crashing, so Sentry never hears about it and the bug hides for weeks. The fix is to call sentry_sdk.capture_exception() inside the handler, then re-raise or return a proper error, so the event is recorded and the caller still knows something failed.

Third, turning on error capture but never setting traces_sample_rate. The symptom is that errors arrive fine, but the performance pages stay empty and slow checkout calls have no trace to inspect. The fix is to set traces_sample_rate to a small value such as 0.1 in production, so a sample of requests produces traces without flooding your quota.

Frequently Asked Questions

Is Sentry free to start with? Yes, with a monthly event allowance that suits a small app. Check the pricing page first, because a noisy error loop can burn through it fast.

Does Sentry slow down my Python app? Barely. The SDK sends events in the background, and the cost per request is small. Capture every request with tracing, though, and you will feel it.

Can I test capture without a real Sentry account? Yes. This post does exactly that, with a before_send hook saving events into a list and a placeholder DSN. A real project DSN sends events to the dashboard.

Does Sentry work with Django, Flask, and FastAPI? Yes, the Python SDK ships integrations for all three, attaching automatically once initialised. The same idea applies beyond Python: a JavaScript frontend uses the JavaScript SDK the same way.

What to remember

  • Call sentry_sdk.init() first, before any code that can crash, or early errors are never reported.
  • Assign an owner for the issues inbox, or captured events pile up unread.
  • Validate incoming data so a missing field fails at the door, not at checkout.
  • Sample traces and set alert rules, or a noisy loop eats your quota.
  • Test capture locally with before_send before trusting production.

Where this leaves you

Sentry error tracking earns its place the day strangers can break your app in ways you never tested. The demo proved the two things that matter: an uninitialised SDK captures nothing, and the same crash after init produces a real event with the exception type and the missing key attached. That is the whole job. Start with the free tier, wire init into your entry point, and check the issues page after your next deploy. If the inbox stays quiet, you have peace of mind. If it fills up, you have a list of real bugs, which is the better outcome.

Further reading

Waqas Shahid is a software engineer from Karachi with more than 12 years of experience, including 6+ years in engineering leadership. He writes The Practical Developer.

Originally published at The Practical Developer

No comments yet. Be the first to comment.