Skip to content

feat: auto-detect raised HTTPExceptions for OpenAPI docs#4619

Open
Br1an67 wants to merge 6 commits intolitestar-org:mainfrom
Br1an67:feat/auto-document-exceptions
Open

feat: auto-detect raised HTTPExceptions for OpenAPI docs#4619
Br1an67 wants to merge 6 commits intolitestar-org:mainfrom
Br1an67:feat/auto-document-exceptions

Conversation

@Br1an67
Copy link
Copy Markdown
Contributor

@Br1an67 Br1an67 commented Mar 1, 2026

Description

When a route handler raises HTTPException subclasses but does not explicitly declare them via the raises parameter, those error responses are currently missing from the generated OpenAPI schema.

This PR adds AST-based auto-detection of raised HTTPException subclasses in route handlers. The OpenAPI response generator now automatically scans handler source code for raise statements targeting HTTPException subclasses and includes the corresponding error responses in the schema.

Behavior:

  • When raises is not set on a handler → automatically detect raised exceptions via AST inspection
  • When raises is explicitly set → use only the declared exceptions (no auto-detection), preserving full developer control
  • Detection gracefully falls back to an empty list if source inspection fails (e.g., dynamically generated handlers)

Changes:

  • New module litestar/_openapi/exception_detection.py with detect_exceptions_from_handler()
  • Modified litestar/_openapi/responses.py to call auto-detection in create_responses()
  • Added unit tests in tests/unit/test_openapi/test_exception_detection.py

Closes

Closes #2416


📚 Documentation preview 📚: https://litestar-org.github.io/litestar-docs-preview/4619

Add AST-based detection of HTTPException subclasses raised in route
handlers. When a handler does not explicitly declare 'raises', the
OpenAPI response schema generation now automatically scans the handler's
source code for 'raise' statements and includes the corresponding error
responses in the generated schema.

This is opt-out: explicitly setting 'raises' on a handler disables
auto-detection, giving full control to the developer.

New module: litestar/_openapi/exception_detection.py
Modified: litestar/_openapi/responses.py (integration point)
Tests: tests/unit/test_openapi/test_exception_detection.py
@Br1an67 Br1an67 requested review from a team as code owners March 1, 2026 07:17
@github-actions github-actions bot added area/openapi This PR involves changes to the OpenAPI schema area/private-api This PR involves changes to the privatized API size: small type/feat pr/external Triage Required 🏥 This requires triage labels Mar 1, 2026
@codecov
Copy link
Copy Markdown

codecov bot commented Mar 1, 2026

Codecov Report

❌ Patch coverage is 96.49123% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 97.88%. Comparing base (e68dd0b) to head (d8b177c).
⚠️ Report is 12 commits behind head on main.

Files with missing lines Patch % Lines
litestar/_openapi/exception_detection.py 95.83% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4619      +/-   ##
==========================================
- Coverage   97.88%   97.88%   -0.01%     
==========================================
  Files         298      299       +1     
  Lines       15375    15432      +57     
  Branches     1730     1743      +13     
==========================================
+ Hits        15050    15105      +55     
- Misses        184      185       +1     
- Partials      141      142       +1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Br1an67 added 2 commits March 1, 2026 15:44
- Remove unused import (fixes pre-commit lint failure)
- Add tests for uninspectable callables and bare raise statements
- Add test for attribute-style raise (module.Exception)
- Add integration test for auto-detection in ResponseFactory
- Replace non-deterministic assertion with proper test
Add tests for uncovered branches:
- Subscript-style call func (neither ast.Name nor ast.Attribute)
- Subscript-style raise (neither ast.Call nor ast.Name)
- Duplicate exception skipped in create_responses()
@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 1, 2026

Documentation preview will be available shortly at https://litestar-org.github.io/litestar-docs-preview/4619

Copy link
Copy Markdown
Member

@provinzkraut provinzkraut left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this submission. I do have a few concerns:

Performance impact
Doing this for every handler can get very costly for bigger applications, as it could increase startup time drastically. One approach to mitigating this might be using tokenize instead of ast

User expectations
If we add a feature that does something automatically, users will expect to work everywhere. HTTPExceptions can be raised at every point during the request processing chain, for example in dependencies and guards. As a user, I would expect guards in particular to work, since they're part of the authorisation chain.

However, making this work everywhere is going to be quite tricky.

Hidden magic
In general, Litestar tries not to do too much magic, and be explicit about things. This design goes quite a bit against that.


Assuming the goal is "Ensure that error responses are properly documented", I think this might be better suited for a linter. We've talked about adding a check command to Litestar's CLI before, where something like this would be a natural fit.

Br1an67 and others added 3 commits March 1, 2026 20:26
…allables

- Move inline import of HTTPException to top-level module imports
- Add _resolve_callable() helper to handle bound methods, classmethods,
  staticmethods, and classes (inspects __init__)
- Add tests for bound method and class callable detection

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace hasattr check + direct __func__ access with getattr fallback
to satisfy pyright type checking.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Replace ast-based scanning with tokenize for lower overhead
- Add OpenAPIConfig.auto_detect_exceptions (default: False) so the
  feature is explicitly opt-in
- Update tests to enable the new config flag
@Br1an67
Copy link
Copy Markdown
Contributor Author

Br1an67 commented Mar 3, 2026

Thanks for the thoughtful review — all valid concerns.

I've pushed an update that addresses them:

  1. Performance — Switched from ast.parse to tokenize, which is significantly cheaper (no full tree construction).
  2. Hidden magic — The feature is now opt-in via OpenAPIConfig(auto_detect_exceptions=True). Off by default, so no surprise behavior.
  3. Guards/dependencies — Acknowledged limitation: only the handler body is scanned. This is documented in the config field's docstring.

If you'd still prefer this to live as a CLI check command rather than a config option, I'm happy to pivot. Let me know which direction you'd prefer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/openapi This PR involves changes to the OpenAPI schema area/private-api This PR involves changes to the privatized API pr/external size: small Triage Required 🏥 This requires triage type/feat

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Enhancement: Automatically document exceptions

2 participants