{"record":{"id":"ce2dd9947f6a6e08","repo":"Fosowl/agenticSeek","slug":"openai-response-is-empty","errorCode":null,"errorMessage":"OpenAI response is empty.","messagePattern":"OpenAI response is empty\\.","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"sources/llm_provider.py","lineNumber":243,"sourceCode":"        base_url = self.server_ip\n        if self.is_local and self.in_docker:\n            try:\n                host, port = base_url.split(':')\n            except Exception as e:\n                port = \"8000\"\n            client = OpenAI(api_key=self.api_key, base_url=f\"{self.internal_url}:{port}\")\n        elif self.is_local:\n            client = OpenAI(api_key=self.api_key, base_url=f\"http://{base_url}\")\n        else:\n            client = OpenAI(api_key=self.api_key)\n\n        try:\n            response = client.chat.completions.create(\n                model=self.model,\n                messages=history,\n            )\n            if response is None:\n                raise Exception(\"OpenAI response is empty.\")\n            thought = response.choices[0].message.content\n            if verbose:\n                print(thought)\n            return thought\n        except Exception as e:\n            raise Exception(f\"OpenAI API error: {str(e)}\") from e\n\n    def anthropic_fn(self, history, verbose=False):\n        \"\"\"\n        Use Anthropic to generate text.\n        \"\"\"\n        from anthropic import Anthropic\n\n        client = Anthropic(api_key=self.api_key)\n        system_message = None\n        messages = []\n        for message in history:\n            clean_message = {'role': message['role'], 'content': message['content']}","sourceCodeStart":225,"sourceCodeEnd":261,"githubUrl":"https://github.com/Fosowl/agenticSeek/blob/ae57a2357745a9706cb12d0fd76d954c84d166fa/sources/llm_provider.py#L225-L261","documentation":"Raised in openai_fn (sources/llm_provider.py:243) when the OpenAI SDK's chat.completions.create() returns None instead of a ChatCompletion object. The library treats a None response as an empty/unusable completion and raises immediately. In practice this is rare with the official OpenAI client, but it guards against proxies/compatible endpoints returning an empty body. The error is then re-wrapped by the generic handler at line 249, so the developer usually sees 'OpenAI API error: OpenAI response is empty.'","triggerScenarios":"client.chat.completions.create(model=self.model, messages=history) returns None — typically when pointing base_url at a local/compatible server (is_local path builds base_url from server_ip, port defaulting to 8000) that returns a 200 with an empty body, or a proxy that swallows the response.","commonSituations":"Using a local OpenAI-compatible server (vLLM, llama.cpp server, LM Studio) on port 8000 that failed to generate but returned an empty 200; misconfigured server_ip in config.ini hitting the wrong endpoint; an API proxy/gateway dropping the response body; SDK/server version mismatch producing a non-standard response that deserializes to None.","solutions":["Verify the endpoint actually serves the model: curl the /v1/chat/completions route with the same model name and inspect the raw JSON body.","Check the base_url in config.ini / server_ip — for local servers it must be 'host:port' (port defaults to 8000) and the server must expose an OpenAI-compatible API.","Confirm the model name exists on the endpoint (list models via GET /v1/models); a wrong model can make some servers return empty responses.","Upgrade the openai Python SDK so response parsing matches the server's response format.","If using a proxy/gateway, test the same request directly against the provider to rule out the proxy returning empty bodies."],"exampleFix":"// before (config.ini for local provider)\nserver_ip = localhost:9999\n\n// after\nserver_ip = localhost:8000  ; port where the OpenAI-compatible server actually listens","handlingStrategy":"type-guard","validationCode":"import httpx\n\ndef assert_openai_compatible_endpoint(base_url, api_key, model, timeout=5):\n    r = httpx.post(\n        f\"{base_url.rstrip('/')}/chat/completions\",\n        headers={\"Authorization\": f\"Bearer {api_key}\"},\n        json={\"model\": model, \"messages\": [{\"role\": \"user\", \"content\": \"ping\"}], \"max_tokens\": 1},\n        timeout=timeout,\n    )\n    if not r.content.strip():\n        raise RuntimeError(f\"Endpoint {base_url} returned an empty body for model {model}\")\n    r.raise_for_status()","typeGuard":"from types import SimpleNamespace\n\ndef is_valid_chat_completion(response) -> bool:\n    \"\"\"True only if the response has usable choices[0].message.content text.\"\"\"\n    if response is None:\n        return False\n    choices = getattr(response, \"choices\", None)\n    if not choices:\n        return False\n    message = getattr(choices[0], \"message\", None)\n    return message is not None and isinstance(getattr(message, \"content\", None), str)\n\n# usage\nif not is_valid_chat_completion(response):\n    raise RuntimeError(\"OpenAI response is empty or malformed.\")","tryCatchPattern":"try:\n    thought = provider.openai_fn(history)\nexcept Exception as e:\n    cause = e.__cause__\n    if \"response is empty\" in str(e).lower():\n        # local/compatible server returned empty body: check endpoint & model\n        raise RuntimeError(\n            \"LLM endpoint returned an empty response; verify server_ip/base_url \"\n            \"and that the model is loaded.\"\n        ) from cause\n    raise  # propagate other API errors unchanged","preventionTips":["Ping the endpoint with curl and confirm a non-empty JSON body before wiring it into config.ini.","Pin and regularly upgrade the openai SDK so responses deserialize predictably.","When using local OpenAI-compatible servers (vLLM, llama.cpp, LM Studio), verify the model is loaded and the model name matches exactly.","Check response content with a type guard before accessing .choices[0].message.content.","Bypass or correctly configure proxies that can return empty 200 responses."],"tags":["openai","empty-response","api","local-server","response-validation"],"backgroundTag":"empty-api-response","analyzedSha":"ae57a2357745a9706cb12d0fd76d954c84d166fa","analyzedAt":"2026-08-30T02:49:05.834Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}