anyio.BrokenResourceError when using BaseHTTPMiddleware
See original GitHub issueChecklist
- The bug is reproducible against the latest release and/or
master
. - There are no similar issues or pull requests to fix it yet.
Describe the bug
An anyio.BrokenResourceError is observed when using a very simple custom Middleware base on BaseHTTPMiddleware.
To reproduce
Server
import uvicorn
from starlette.applications import Starlette
from starlette.middleware import Middleware
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.responses import Response
from starlette.routing import Route
from starlette.requests import Request
class MyMiddleware(BaseHTTPMiddleware):
async def dispatch(
self, request: Request, call_next
) -> Response:
return await call_next(request)
async def ping(request):
return Response("Some Text")
app = Starlette(
debug=False,
routes=[
Route('/ping', ping, methods=['GET', 'POST']),
],
middleware=[
Middleware(MyMiddleware),
]
)
uvicorn.run(app, host='0.0.0.0', port=8000, access_log=True)
Client
from http.client import HTTPConnection
def ping(x):
con = HTTPConnection('0.0.0.0', 8000)
con.request('GET', f'/ping?id={x}')
z = [
ping(y)
for y in range(10)
]
Expected behavior
No exceptions, responses returned
Actual behavior
An anyio.BrokenResourceError is raised
Debugging material
Traceback
``` ERROR: Exception in ASGI application Traceback (most recent call last): File "/home/plaid/py39/lib/python3.9/site-packages/uvicorn/protocols/http/httptools_impl.py", line 371, in run_asgi result = await app(self.scope, self.receive, self.send) File "/home/plaid/py39/lib/python3.9/site-packages/uvicorn/middleware/proxy_headers.py", line 59, in __call__ return await self.app(scope, receive, send) File "/home/plaid/py39/lib/python3.9/site-packages/starlette/applications.py", line 112, in __call__ await self.middleware_stack(scope, receive, send) File "/home/plaid/py39/lib/python3.9/site-packages/starlette/middleware/errors.py", line 181, in __call__ raise exc File "/home/plaid/py39/lib/python3.9/site-packages/starlette/middleware/errors.py", line 159, in __call__ await self.app(scope, receive, _send) File "/home/plaid/py39/lib/python3.9/site-packages/starlette/middleware/base.py", line 57, in __call__ task_group.cancel_scope.cancel() File "/home/plaid/py39/lib/python3.9/site-packages/anyio/_backends/_asyncio.py", line 564, in __aexit__ raise exceptions[0] File "/home/plaid/py39/lib/python3.9/site-packages/starlette/middleware/base.py", line 30, in coro await self.app(scope, request.receive, send_stream.send) File "/home/plaid/py39/lib/python3.9/site-packages/starlette/exceptions.py", line 82, in __call__ raise exc File "/home/plaid/py39/lib/python3.9/site-packages/starlette/exceptions.py", line 71, in __call__ await self.app(scope, receive, sender) File "/home/plaid/py39/lib/python3.9/site-packages/starlette/routing.py", line 656, in __call__ await route.handle(scope, receive, send) File "/home/plaid/py39/lib/python3.9/site-packages/starlette/routing.py", line 259, in handle await self.app(scope, receive, send) File "/home/plaid/py39/lib/python3.9/site-packages/starlette/routing.py", line 64, in app await response(scope, receive, send) File "/home/plaid/py39/lib/python3.9/site-packages/starlette/responses.py", line 139, in __call__ await send({"type": "http.response.body", "body": self.body}) File "/home/plaid/py39/lib/python3.9/site-packages/starlette/exceptions.py", line 68, in sender await send(message) File "/home/plaid/py39/lib/python3.9/site-packages/anyio/streams/memory.py", line 205, in send raise BrokenResourceError anyio.BrokenResourceError ```Environment
- OS: Ubuntu
18.04
- Python version:
3.9.6
- Starlette version:
0.16.0
Issue Analytics
- State:
- Created 2 years ago
- Reactions:1
- Comments:6 (2 by maintainers)
Top Results From Across the Web
RuntimeError: No response returned in FastAPI when refresh ...
This is due to how starlette uses anyio memory object streams with StreamingResponse in BaseHTTPMiddleware . When you cancel a request, ...
Read more >API reference — AnyIO 3.6.2 documentation - Read the Docs
If your code needs AnyIO 2 compatibility, you can keep using this until AnyIO 4. ... BrokenResourceError – if this stream has been...
Read more >Middleware - Starlette
An abstract class that allows you to write ASGI middleware against a request/response interface. Usage. To implement a middleware class using BaseHTTPMiddleware ......
Read more >Release Notes - FastAPI
It upgrades the version of Starlette to 0.15.0 , now based on AnyIO, and the internal async components in FastAPI are now based...
Read more >fastapi 0.70.1, middleware bug
BrokenResourceError · Issue #4041 · tiangolo/fastapi ... I searched the FastAPI documentation, with the integrated search... GitHubtiangolo.
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
I’m still seeing this in my sentry logs. It seems to occur when the server is overloaded, and the client times out / dies. This is on
anyio==3.6.1 fastapi==0.83.0 starlette=0.19.1 uvicorn==0.18.3
.I managed to reproduce it with a slightly modified server app:
and this stressor script:
Running
./broken_resource.sh 10
seems tolerable, as I increase the count, I start getting tracebacks. Locally, I see:Traceback for local example
but in my production application I’m still seeing the
BrokenResourceError
. I’m thinking that might be due to differences in middleware.https://github.com/agronholm/anyio/blob/48efdec45e70a833cc939c1d2752f24e29d1bf0b/src/anyio/streams/memory.py#L220-L221
Traceback I see in production
According to Sentry, the state of
self
at the time of the error is(I’m guessing this is just after
.pop()
is called, which is why waiting_senders is empty dict) the ASGI message is{body: b'true', type: 'http.response.body'}
(my endpoint in prod is justreturn True
) and the send_event is of type<anyio._backends._asyncio.Event object at 0x7f68dcc31be0>
Maybe this is AnyIO’s problem at this point? Possibly: https://github.com/agronholm/anyio/issues/440
If you remove the Middleware, or add other Middleware such as
Middleware(SessionMiddleware, secret_key='123')
, or downgrade to Starlette 0.14.* no exception is raised. Surely it should gracefully handle that a connection has been aborted and not generate a Traceback?