Hacktoberfest 2026: los issues que los mantenedores marcaron para octubre, abiertos y aptos para principiantes. Explorar issues de Hacktoberfest

StarletteIntegration eagerly drains the ASGI receive channel for request bodies under max_request_body_size, breaking handlers that read the body themselves afterward

Abierto
#7,285 3 comentarios 0 reacciones 0 asignados Ver en GitHub

Nadie ha tomado este issue todavía.

Evaluación

Dificultad
4/5
Tiempo estimado
3-5 días
Aptitud para principiantes
48/100
Tipo de issue
Error
Claridad
Bien especificado
Estado de actividad
Activo
Stack tecnológico
python

Línea de trabajo

Empieza por StarletteIntegration.patch_request_response() y StarletteRequestExtractor.extract_request_info(), y después inspecciona request_body_within_bounds() en _wsgi_common.py para rastrear cuándo se consume el canal de recepción de ASGI. Reprodúcelo con la aplicación de Starlette proporcionada y compara las solicitudes inferiores y superiores a 10.000 bytes; se considera completado cuando ambas terminan al leer el endpoint el body mediante una nueva StarletteRequest.

Escrito por el modelo de indexación a partir del texto del issue.

Descripción

Bug Integration: Starlette/FastAPI Python

Summary

StarletteIntegration.patch_request_response() wraps every Starlette route endpoint. Before the real endpoint runs, StarletteRequestExtractor.extract_request_info() calls await self.request.body() (via .form()) whenever content_length is within max_request_body_size (default "medium"content_length <= 10_000 bytes, see request_body_within_bounds() in _wsgi_common.py). That fully drains the request's raw ASGI receive() channel, purely to populate breadcrumb/event data.

If the wrapped endpoint later performs its own manual body read against the same receive callable (rather than through Starlette's cached Request.body()/.stream()), that second read hangs forever: the ASGI transport already sent its final http.request message with more_body: False, so there is nothing left to receive, and (on a normal keep-alive connection) no http.disconnect will arrive either. The request just hangs until something upstream times out.

This is exactly what happens with Streamlit's st.file_uploader (streamlit/web/server/starlette/starlette_routes.py, _upload_put): to enforce a streaming size cap without buffering the whole upload in memory, it builds a new StarletteRequest(request.scope, limited_receive) where limited_receive calls await request.receive() directly. Sentry has already exhausted that channel for any upload under ~10,000 bytes, so the second read blocks indefinitely — every small file upload hangs, every upload over ~10KB (where Sentry skips body capture) works fine. Full writeup and a minimal, Sentry-only repro (isolating exactly which integration is responsible) filed against Streamlit: https://github.com/streamlit/streamlit/issues/16697, gist: https://gist.github.com/tbrambor/d41b40950a0061ca404fc0d67e4768ed

This isn't Streamlit-specific. Any ASGI handler that reads its own request body (streaming multipart parsers, chunked uploads, proxies, WebSocket-adjacent code, etc.) rather than going through Starlette's Request.body()/.form()/.stream() cache will break the same way, silently, as a hang rather than an error — for any request whose Content-Length happens to fall under max_request_body_size. The failure mode (indefinite hang, not an exception) makes it especially hard to trace back to Sentry.

How do you use Sentry?

Self-hosted/on-premise, via sentry-sdk in a Starlette/FastAPI-family ASGI app.

Version

sentry-sdk==2.61.1, starlette==1.3.1 (as bundled with streamlit==1.61.1), Python 3.12.

Steps to Reproduce

"""
pip install starlette==1.3.1 sentry-sdk==2.61.1 uvicorn
python repro.py
Then: curl -s -X POST http://localhost:8000/upload -F "file=@small.txt" --max-time 5
(any file under 10000 bytes hangs and times out; a file over 10000 bytes succeeds)
"""
import sentry_sdk
sentry_sdk.init(dsn=None)

from starlette.applications import Starlette
from starlette.requests import Request as StarletteRequest
from starlette.responses import PlainTextResponse
from starlette.routing import Route


async def upload(request):
    # Mirrors Streamlit's _upload_put: read the body through a fresh
    # Request wrapping the same raw ASGI `receive`, instead of the
    # cached Request.body()/.form(). This is what breaks once Sentry
    # has already drained `receive` for content_length <= 10000 bytes.
    limited_request = StarletteRequest(request.scope, request.receive)
    form = await limited_request.form()
    return PlainTextResponse("ok")


app = Starlette(routes=[Route("/upload", upload, methods=["POST"])])

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)
  1. Run the script above.
  2. curl -X POST http://localhost:8000/upload -F "file=@small.txt" where small.txt is under 10,000 bytes — hangs indefinitely (times out client-side).
  3. Same request with a file over 10,000 bytes — succeeds immediately.
  4. Comment out sentry_sdk.init(dsn=None) — both sizes succeed immediately.

Expected Result

The request completes regardless of file size, and regardless of whether the endpoint reads the body itself vs. relying on Sentry having already read it.

Actual Result

Requests with a body at or under max_request_body_size (default 10,000 bytes) hang forever if the endpoint performs its own body/receive read rather than using Starlette's own cached Request.body()/.form(). No exception is raised on either side — it's a silent hang, not an error, which makes it very hard to diagnose from application logs alone.

Lenguaje dominante
Python
Estrellas
2.2k
Forks
672
Merge medio
22 h 47 min
PR fusionados (30 d)
224

Guía de contribución

Abrir la guía de contribución

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Más de getsentry/sentry-python

Todos los issues de getsentry/sentry-python

Issues similares

Más issues de Python

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.