Flask catches view exceptions internally to render its 500 error page, so they never reach Python's sys.excepthook — a generic monitoring SDK sees nothing. Flask fires a got_request_exception signal every time this happens, and that's the correct hook to connect to. With Ravn, this is ravn.init() plus one call to init_app(app) from ravn.integrations.flask.
Same story as Django, different framework: Flask intercepts exceptions raised in a view so it can return an error response, which means the exception's journey ends inside Flask and never reaches the process-level exception hook. If your monitoring setup relies purely on sys.excepthook, a Flask app can 500 all day without a single event showing up.
Why doesn't Flask report exceptions the normal way?
Flask's dispatch machinery wraps every view call in its own error handling so it can render a proper HTTP error response instead of crashing the WSGI worker. Before it does, it sends the got_request_exception signal — powered by the blinker library — with the live exception still accessible. That signal is the integration point.
How do you capture Flask exceptions with Ravn?
import ravn
from ravn.integrations.flask import init_app
from flask import Flask
app = Flask(__name__)
ravn.init(api_key="your_api_key")
init_app(app)
# Every unhandled exception in any view is now captured,
# with the request path and method attached automatically.
Under the hood, it's a thin signal receiver:
def init_app(app) -> None:
from flask import got_request_exception, request
def _handle(sender, exception, **extra):
capture_exception(exception, metadata={
"mechanism": "flask",
"path": request.path,
"method": request.method,
})
got_request_exception.connect(_handle, app, weak=False)
Why does the handler need weak=False?
Flask's signals run on blinker, which by default holds only a weak reference to connected receivers. A local closure with no other strong reference gets garbage-collected almost immediately after the connecting function returns — the signal silently stops firing, with nothing in your logs to tell you it happened. It looks wired up. It isn't. Passing weak=False makes blinker hold a strong reference, so the handler survives for the life of the process.
This is the same failure mode as the Django integration, and it's worth checking for in any hand-rolled Flask signal handler — it's an easy thing to get wrong silently.
Do I need to install blinker separately?
No, if you're on a reasonably current Flask. Blinker has been a required dependency since Flask 2.3, so it's already installed alongside Flask itself in any modern project.
Does this work with blueprints?
got_request_exception is application-wide — it fires for unhandled exceptions regardless of whether the view is registered directly on the app or through a blueprint. No blueprint-specific configuration is needed.
For the framework-agnostic version of this setup, see the Python error monitoring guide, or the equivalent walkthroughs for Django and FastAPI.
Add error monitoring to your Flask app in two lines.
Automatic exception capture, AI root-cause analysis, free to start.
Get Started FreeFrequently asked questions
Does Flask report unhandled exceptions automatically?
No. Flask catches view exceptions internally to render a 500 page, so they never reach sys.excepthook. A tool that only hooks the global exception handler sees nothing from a Flask app.
How do I capture Flask view exceptions?
Connect to Flask's got_request_exception signal, which fires every time Flask catches a view exception. With Ravn this is one call: init_app(app) from ravn.integrations.flask, after ravn.init().
Why does the signal handler need weak=False?
Flask's signals run on blinker, which holds only a weak reference to receivers by default. A local closure gets garbage-collected right after connecting, silently breaking the signal. weak=False forces a strong reference so it stays connected.
Do I need to install blinker separately?
No, if you're on Flask 2.3 or newer — blinker has been a required dependency since then, so it's already installed.
Does this work with Flask blueprints?
Yes. got_request_exception is application-wide, so it fires for unhandled exceptions in views registered directly on the app or through any blueprint.