Skip to content

Don't fail the request with a bare 500 on transient JWT refresh errors - #74722

Open
kjh0623 wants to merge 6 commits into
apache:mainfrom
kjh0623:fix/jwt-refresh-middleware-transient-500
Open

kjh0623 wants to merge 6 commits into
apache:mainfrom
kjh0623:fix/jwt-refresh-middleware-transient-500

Conversation

@kjh0623

@kjh0623 kjh0623 commented Oct 14, 2026

Copy link
Copy Markdown

Re-submission of #70057, which was auto-closed as stale (bot-closed, so I can't reopen it). Same branch, with current main merged in. Earlier review discussion is in #70057.

Problem

JWTRefreshMiddleware.dispatch runs outside the FastAPI exception handlers and only catches HTTPException / AuthManagerRefreshTokenExpiredException. Any other error from _refresh_user() becomes a bare 500. We hit this in production when PgBouncer drops a connection and the user lookup raises OperationalError. Related: #57859.

Fix

Add a final except Exception arm that:

  • logs with log.exception() (ERROR + traceback),
  • continues without injecting the user (the route's auth dependency still validates the token),
  • leaves the cookie untouched.

The catch is broad on purpose: the middleware can't know which exceptions are transient for the configured auth manager.

Testing

New unit test: a non-HTTP error from _refresh_user → the request succeeds, no set-cookie, an ERROR record with exc_info is logged.


Was generative AI tooling used to co-author this PR?
  • Yes (please specify the tool below)

Generated-by: Claude Code following the guidelines

LOGAN\gktxk and others added 5 commits July 18, 2026 07:43
JWTRefreshMiddleware runs outside the FastAPI exception handlers and only
caught HTTPException / AuthManagerRefreshTokenExpiredException. Any other
exception raised while resolving or refreshing the user - notably an
OperationalError when the metadata DB connection is recycled underneath the
API server - propagated to the ASGI layer and surfaced as a bare HTTP 500,
even for requests that did not need the refresh at all.

Treat such errors as "could not refresh this time": log a warning, proceed
without injecting the user (the route's own auth dependency revalidates the
token), and leave the cookie untouched so a later request refreshes once the
backend recovers. HTTPException / token-expiry semantics are unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Failing open on an unexpected error keeps the request alive, but it must not
make a genuine bug in the auth manager quieter than the bare 500 it replaces.
WARNING is easy to miss and a monitor keyed on 5xx would go silent on a real
regression, so switch the unexpected arm to log.exception() - ERROR level with
the traceback - while transient blips stay non-fatal (review feedback from
@SameerMesiah97).

Signed-off-by: kjh0623 <8412070+kjh0623@users.noreply.github.com>
Signed-off-by: kjh0623 <8412070+kjh0623@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@kjh0623
kjh0623 requested a review from vincbeck as a code owner October 14, 2026 11:15
@boring-cyborg boring-cyborg Bot added the area:API Airflow's REST/HTTP API label Oct 14, 2026
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

This branch has not been deployed

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

Labels

area:API Airflow's REST/HTTP API backport-to-v3-4-test Backport to v3-4-test

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants