@@ -156,6 +156,7 @@ def __init__(self, app: ASGIApp) -> None:
156156 self .error_response : Optional [Response ] = None
157157 self .initial_message : Message = {}
158158 self .inject_headers = False
159+ self .started = False
159160
160161 async def send_wrapper (self , message : Message ) -> None :
161162 if message ["type" ] == "http.response.start" :
@@ -164,18 +165,24 @@ async def send_wrapper(self, message: Message) -> None:
164165 self .initial_message = message
165166
166167 elif message ["type" ] == "http.response.body" :
167- if self .error_response :
168- self .initial_message ["status" ] = self .error_response .status_code
169-
170- if self .inject_headers :
171- headers = MutableHeaders (raw = self .initial_message ["headers" ])
172- headers = self .limiter ._inject_asgi_headers (
173- headers , self .request .state .view_rate_limit
174- )
175-
176- # send the http.response.start message just before the http.response.body one,
177- # now that the headers are updated
178- await self .send (self .initial_message )
168+ if not self .started :
169+ # Only modify and send the initial message once, on the first body chunk.
170+ # Streaming responses (e.g. FileResponse) send multiple body chunks;
171+ # re-sending http.response.start on each would cause
172+ # "RuntimeError: ASGI flow error: Response already started".
173+ self .started = True
174+
175+ if self .error_response :
176+ self .initial_message ["status" ] = self .error_response .status_code
177+
178+ if self .inject_headers :
179+ headers = MutableHeaders (raw = self .initial_message ["headers" ])
180+ headers = self .limiter ._inject_asgi_headers (
181+ headers , self .request .state .view_rate_limit
182+ )
183+
184+ await self .send (self .initial_message )
185+
179186 await self .send (message )
180187
181188 async def __call__ (self , scope : Scope , receive : Receive , send : Send ) -> None :
0 commit comments