{"record":{"id":"e0e1ba5a5c09201d","repo":"reflex-dev/reflex","slug":"upload-handler-returned-before-consuming-all-uploa","errorCode":null,"errorMessage":"Upload handler returned before consuming all upload chunks.","messagePattern":"Upload handler returned before consuming all upload chunks\\.","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"packages/reflex-components-core/src/reflex_components_core/core/_upload.py","lineNumber":250,"sourceCode":"            self._condition.notify_all()\n\n    def _raise_if_consumer_finished(self) -> None:\n        \"\"\"Raise if the consumer task exited before draining the iterator.\n\n        Raises:\n            RuntimeError: If the consumer task completed before draining the iterator.\n        \"\"\"\n        if self._consumer_task is None or not self._consumer_task.done():\n            return\n\n        try:\n            task_exc = self._consumer_task.exception()\n        except asyncio.CancelledError as err:\n            task_exc = err\n\n        msg = \"Upload handler returned before consuming all upload chunks.\"\n        if task_exc is not None:\n            raise RuntimeError(msg) from task_exc\n        raise RuntimeError(msg)\n\n    def _wake_waiters(self, task: asyncio.Future[Any]) -> None:\n        \"\"\"Wake any producers or consumers blocked on the iterator condition.\n\n        Args:\n            task: The completed consumer task.\n        \"\"\"\n        task.get_loop().create_task(self._notify_waiters())\n\n    async def _notify_waiters(self) -> None:\n        \"\"\"Notify tasks waiting on the iterator condition.\"\"\"\n        async with self._condition:\n            self._condition.notify_all()\n\n\n@dataclasses.dataclass(kw_only=True, slots=True)\nclass _UploadChunkPart:","sourceCodeStart":232,"sourceCodeEnd":268,"githubUrl":"https://github.com/reflex-dev/reflex/blob/45b8ed5ab735f8a56bbb09a42384f030eb0208e7/packages/reflex-components-core/src/reflex_components_core/core/_upload.py#L232-L268","documentation":"The streaming upload iterator verifies the background consumer task is still alive before enqueueing chunks. When the handler task has finished (returned, errored, or was cancelled) while chunks remain, _raise_if_consumer_finished raises RuntimeError, chained from the task's exception if any.","triggerScenarios":"An async upload handler returns (or raises) without fully draining `async for chunk in upload.iter_chunks()` while the client is still sending data, causing the next push() to detect the dead consumer.","commonSituations":"Handler returns after reading only the first chunk (e.g. `chunk = await it.__anext__(); return`); handler raises inside the loop; handler task cancelled due to timeout.","solutions":["Consume the iterator to completion inside the handler: `async for chunk in it: ...`","If you must stop early, close/cancel the request so the producer stops pushing","Inspect the chained task exception to find the root cause in the handler"],"exampleFix":"// before\nasync def handle(it):\n    first = await it.__anext__()\n    return process(first)  # consumer dies early\n\n// after\nasync def handle(it):\n    async for chunk in it:\n        process(chunk)","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try:\n    async for chunk in it:\n        handle(chunk)\nexcept RuntimeError as e:\n    log.error(\"upload consumer died: %s\", e.__cause__)","preventionTips":["Never return from an upload handler before the async for loop completes","Wrap handler bodies so exceptions drain or cancel the stream"],"tags":["upload","task-lifecycle","streaming"],"backgroundTag":"consumer-failed-mid-stream","analyzedSha":"45b8ed5ab735f8a56bbb09a42384f030eb0208e7","analyzedAt":"2026-08-28T19:25:27.644Z","schemaVersion":2},"datasetVersion":"2026-08-28T21:17:43.275Z"}