tiangolo/fastapi · error · FastAPIError
Response not awaited. There's a high chance that the applica
Error message
Response not awaited. There's a high chance that the application code is raising an exception and a dependency with yield has a block with a bare except, or a block with except Exception, and is not raising the exception again. Read more about it in the docs: https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-with-yield/#dependencies-with-yield-and-except
What it means
Raised by FastAPI's request handler after the dependency AsyncExitStack exits: a `response_awaited` flag is set True only once `await response(scope, receive, send)` completes (routing.py:144-147). If the path operation raised, line 144 raises and the flag stays False; normally that exception propagates out and this branch is never reached. It is reached only when a dependency-with-yield has a `bare except` / `except Exception` that swallows the exception instead of re-raising, so AsyncExitStack.throw unwinds 'cleanly' and control falls through to the `if not response_awaited` guard at routing.py:148-155. In short: your path operation threw, a yielding dependency ate the error, and no response was ever sent.
Source
Thrown at fastapi/routing.py:149
else functools.partial(run_in_threadpool, func) # type: ignore[call-arg]
) # ty: ignore[invalid-assignment]
async def app(scope: Scope, receive: Receive, send: Send) -> None:
request = Request(scope, receive, send)
async def app(scope: Scope, receive: Receive, send: Send) -> None:
# Starts customization
response_awaited = False
async with AsyncExitStack() as request_stack:
scope["fastapi_inner_astack"] = request_stack
async with AsyncExitStack() as function_stack:
scope["fastapi_function_astack"] = function_stack
response = await f(request)
await response(scope, receive, send)
# Continues customization
response_awaited = True
if not response_awaited:
raise FastAPIError(
"Response not awaited. There's a high chance that the "
"application code is raising an exception and a dependency with yield "
"has a block with a bare except, or a block with except Exception, "
"and is not raising the exception again. Read more about it in the "
"docs: https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-with-yield/#dependencies-with-yield-and-except"
)
# Same as in Starlette
await wrap_app_handling_exceptions(app, request)(scope, receive, send)
return app
# Copy of starlette.routing.websocket_session modified to include the
# dependencies' AsyncExitStack
def websocket_session(
func: Callable[[WebSocket], Awaitable[None]],
) -> ASGIApp:View on GitHub (pinned to 42a41db11f)
Solutions
- In every `yield` dependency, re-raise inside `except` blocks: `except Exception: ...; raise`.
- Prefer `try / finally` for teardown so cleanup cannot accidentally swallow the propagating exception.
- Narrow `except` to specific exception types instead of bare `except` or `except Exception`.
- Add a CI/lint check that flags `yield` functions containing `except` without a following `raise`.
- Reproduce with the failing endpoint and step through the dependency teardown to find the swallowing `except`.
Example fix
# before
def get_db():
db = SessionLocal()
try:
yield db
except Exception:
logging.exception("ignored") # swallows the request error
finally:
db.close()
# after
def get_db():
db = SessionLocal()
try:
yield db
except Exception:
logging.exception("will re-raise")
raise
finally:
db.close() Defensive patterns
Strategy: validation
Validate before calling
import ast, inspect, textwrap
def yield_deps_swallow_exceptions(func) -> list[str]:
"""Best-effort static check: flag yield-funcs whose except blocks lack raise."""
src = textwrap.dedent(inspect.getsource(func))
tree = ast.parse(src)
problems = []
for node in ast.walk(tree):
if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)) and any(
isinstance(n, ast.Yield) for n in ast.walk(node)
):
for tryn in [n for n in ast.walk(node) if isinstance(n, ast.Try)]:
for handler in tryn.handlers:
has_raise = any(isinstance(n, ast.Raise) for n in ast.walk(handler))
bare = handler.type is None
broad = isinstance(handler.type, ast.Name) and handler.type.id == "Exception"
if (bare or broad) and not has_raise:
problems.append(f"{func.__name__}:{handler.lineno} swallows without raise")
return problems
# usage at startup / in tests
# assert yield_deps_swallow_exceptions(get_db) == [] Try / catch
# The response was never sent, so the connection is already broken.
# Catch only to log and ensure the process stays healthy; you cannot
# recover the response.
from fastapi import FastAPI
from fastapi.exceptions import FastAPIError
app = FastAPI()
@app.exception_handler(FastAPIError)
async def _handle(request, exc):
logging.critical("FastAPI routing error: %s", exc)
# surface a clean 500; the socket may already be closed
from fastapi.responses import JSONResponse
return JSONResponse({"detail": "internal error"}, status_code=500) Prevention
- Always follow `except` in a yield dependency with `raise`.
- Use `try / finally` for teardown rather than `try / except`.
- Never use bare `except` or `except Exception` in a generator that `yield`s a dependency value.
- Add a unit test that raises from a path operation and asserts the dependency sees the exception (and that the client still gets a proper error response).
When it happens
Trigger: A `yield`-based dependency (e.g. `def get_db(): try: yield db except Exception: log(...)` without `raise`) combined with a path operation or nested dependency that raises during the request. Also triggered when the dependency's teardown uses `except` to swallow the GeneratorExit/exception injected by the AsyncExitStack on unwind.
Common situations: Session/transaction dependencies that log-and-swallow DB errors; porting sync `yield` generators that used broad `except`; cleanup code written as `try/except` instead of `try/finally`; a sub-dependency raising while a parent yield-dep catches everything 'to keep the app alive'.
Related errors
- Owner error: {e}
- X-Token header invalid
- No Jessica token provided
- X-Token header invalid
- X-Key header invalid
AI-assisted analysis of tiangolo/fastapi@42a41db11f (2026-08-04).
Data as JSON: /data/errors/054b6a3a7e4f2c4d.json.
Report an issue: GitHub.