{"record":{"id":"aac3bc0e959eedef","repo":"harry0703/MoneyPrinterTurbo","slug":"empty-content-in-stream-response","errorCode":null,"errorMessage":"Empty content in stream response","messagePattern":"Empty content in stream response","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"app/services/llm.py","lineNumber":377,"sourceCode":"                api_key=api_key,\n                base_url=base_url,\n            )\n            response = client.chat.completions.create(\n                model=model_name,\n                messages=[{\"role\": \"user\", \"content\": prompt}],\n                extra_body={\"enable_thinking\": False},\n                stream=True,\n            )\n            if response:\n                for chunk in response:\n                    if not chunk.choices:\n                        continue\n                    delta = chunk.choices[0].delta\n                    if delta and delta.content:\n                        content += delta.content\n\n                if not content.strip():\n                    raise ValueError(\"Empty content in stream response\")\n\n                return _normalize_text_response(content, llm_provider)\n            else:\n                raise Exception(f\"[{llm_provider}] returned an empty response\")\n\n        client = OpenAI(\n            api_key=api_key,\n            base_url=base_url,\n        )\n\n        response = client.chat.completions.create(\n            model=model_name, messages=[{\"role\": \"user\", \"content\": prompt}]\n        )\n        if response:\n            if isinstance(response, ChatCompletion):\n                return _extract_chat_completion_text(response, llm_provider)\n            else:\n                raise Exception(","sourceCodeStart":359,"sourceCodeEnd":395,"githubUrl":"https://github.com/harry0703/MoneyPrinterTurbo/blob/1f9f19c2021a68d04df228f33e9099a0c947f6f8/app/services/llm.py#L359-L395","documentation":"Raised in the modelscope branch after streaming completed: it iterated all chunks with stream=True and enable_thinking=False, accumulated delta.content into a string, and the result was empty or whitespace-only. The HTTP call succeeded but produced no readable text.","triggerScenarios":"ModelScope chat.completions.create(stream=True, extra_body={'enable_thinking': False}) yields only chunks with empty choices, empty delta, or role-only deltas — model server returned empty content, thinking-only output that was suppressed, content moderation filtered everything, or wrong model id for the endpoint.","commonSituations":"Using a ModelScope reasoning model with enable_thinking=False where the server still emits only thinking tokens; free-tier ModelScope inference (API-Inference) returning empty streams under load; model_name mismatch with the ModelScope model id (e.g. missing 'modelscope/' prefix or owner path); base_url not pointing at the ModelScope OpenAI-compatible endpoint.","solutions":["Retry once via the existing retry loop — transient empty streams occur on the free ModelScope inference tier","Verify base_url is https://api-inference.modelscope.cn/v1 (or your region's equivalent) and model_name is the full ModelScope model id","Try the same call with enable_thinking=True to see if the model only produces reasoning tokens; if so, switch to a non-reasoning model","Test with curl using the same stream payload to inspect raw SSE chunks","If persistent, switch llm_provider to another OpenAI-compatible provider"],"exampleFix":"# before\nextra_body={\"enable_thinking\": False},\nstream=True,\n\n# after (capture finish_reason for diagnosis)\nfor chunk in response:\n    if not chunk.choices:\n        continue\n    delta = chunk.choices[0].delta\n    if delta and delta.content:\n        content += delta.content\n    finish = chunk.choices[0].finish_reason\nif not content.strip():\n    raise ValueError(f\"Empty content in stream response (finish_reason={finish})\")","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"except ValueError as e: if 'Empty content in stream' in str(e): retry — empty streams from the free ModelScope tier are frequently transient; after N retries switch model or provider","preventionTips":["Prefer non-reasoning models on ModelScope when using enable_thinking=False","Smoke-test new model ids with a 1-line prompt first","Capture finish_reason of the last chunk for diagnosis"],"tags":["llm","modelscope","streaming","empty-response"],"backgroundTag":null,"analyzedSha":"1f9f19c2021a68d04df228f33e9099a0c947f6f8","analyzedAt":"2026-08-14T19:41:05.568Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}