{"record":{"id":"b001bef90c92bd3f","repo":"FoundationAgents/OpenManus","slug":"empty-response-from-streaming-llm","errorCode":null,"errorMessage":"Empty response from streaming LLM","messagePattern":"Empty response from streaming LLM","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"app/llm.py","lineNumber":451,"sourceCode":"                return response.choices[0].message.content\n\n            # Streaming request, For streaming, update estimated token count before making the request\n            self.update_token_count(input_tokens)\n\n            response = await self.client.chat.completions.create(**params, stream=True)\n\n            collected_messages = []\n            completion_text = \"\"\n            async for chunk in response:\n                chunk_message = chunk.choices[0].delta.content or \"\"\n                collected_messages.append(chunk_message)\n                completion_text += chunk_message\n                print(chunk_message, end=\"\", flush=True)\n\n            print()  # Newline after streaming\n            full_response = \"\".join(collected_messages).strip()\n            if not full_response:\n                raise ValueError(\"Empty response from streaming LLM\")\n\n            # estimate completion tokens for streaming response\n            completion_tokens = self.count_tokens(completion_text)\n            logger.info(\n                f\"Estimated completion tokens for streaming response: {completion_tokens}\"\n            )\n            self.total_completion_tokens += completion_tokens\n\n            return full_response\n\n        except TokenLimitExceeded:\n            # Re-raise token limit errors without logging\n            raise\n        except ValueError:\n            logger.exception(f\"Validation error\")\n            raise\n        except OpenAIError as oe:\n            logger.exception(f\"OpenAI API error\")","sourceCodeStart":433,"sourceCodeEnd":469,"githubUrl":"https://github.com/FoundationAgents/OpenManus/blob/52a13f2a57d8c7f6737eefb02ccf569594d44273/app/llm.py#L433-L469","documentation":"Raised in LLM.ask_with_tools() streaming branch when every SSE chunk's delta.content was empty, so the joined completion text is empty after strip(). It mirrors the non-streaming empty-response check: the request technically succeeded but produced zero visible tokens.","triggerScenarios":"Calling ask_with_tools(..., stream=True) where all chunks have delta.content None/\"\" — e.g. reasoning models streaming only reasoning deltas, max_tokens exhausted before any text token, or a gateway stripping content from chunks.","commonSituations":"Streaming with a reasoning model without enough max_completion_tokens; provider sending only role/finish chunks; proxies that filter streamed content; moderation-blocked streams.","solutions":["Raise max_tokens / max_completion_tokens so the model reaches the content phase","Retry once — transient empty streams are common on flaky endpoints","Log the raw chunks to confirm whether delta.reasoning_content or refusal fields carry the output, and handle those cases explicitly"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try:\n    text = await llm.ask_with_tools(messages, tools, stream=True)\nexcept ValueError as e:\n    if \"Empty response from streaming\" in str(e):\n        text = await llm.ask_with_tools(messages, tools, stream=False)  # fall back to non-streaming\n    else:\n        raise","preventionTips":["Give reasoning models enough max_completion_tokens to reach the content phase","Fall back to non-streaming when a stream yields nothing","Capture and inspect chunk shapes once when integrating a new provider"],"tags":["llm","streaming","response","retry"],"backgroundTag":null,"analyzedSha":"52a13f2a57d8c7f6737eefb02ccf569594d44273","analyzedAt":"2026-08-15T02:33:49.993Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}