Middleware written by subclassing BaseHTTPMiddleware, which is what @app.middleware("http") produces in FastAPI, runs the downstream application in a separate anyio task. Context variables are copied into a task when it starts, so a ContextVar set in the middleware before calling call_next is not visible to the route handler, and one set by the handler is not visible to the middleware afterwards.
This silently defeats the common pattern of stashing a request id or tenant in a contextvar from middleware for the logger to pick up. The value reads as the default everywhere downstream, with no error.
The same wrapper also buffers through a queue, which interferes with StreamingResponse and with background tasks that expect the response to have been sent. Write the middleware as raw ASGI instead: a callable taking scope, receive, send that sets the contextvar and awaits the inner app. That runs in the same task, so context propagates, streaming stays lazy, and there is no extra queue. Starlette's own middlewares are written this way for the same reasons.