Fosowl/agenticSeek · error · Exception
OpenAI response is empty.
Error message
OpenAI response is empty.
What it means
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.'
Source
Thrown at sources/llm_provider.py:243
base_url = self.server_ip
if self.is_local and self.in_docker:
try:
host, port = base_url.split(':')
except Exception as e:
port = "8000"
client = OpenAI(api_key=self.api_key, base_url=f"{self.internal_url}:{port}")
elif self.is_local:
client = OpenAI(api_key=self.api_key, base_url=f"http://{base_url}")
else:
client = OpenAI(api_key=self.api_key)
try:
response = client.chat.completions.create(
model=self.model,
messages=history,
)
if response is None:
raise Exception("OpenAI response is empty.")
thought = response.choices[0].message.content
if verbose:
print(thought)
return thought
except Exception as e:
raise Exception(f"OpenAI API error: {str(e)}") from e
def anthropic_fn(self, history, verbose=False):
"""
Use Anthropic to generate text.
"""
from anthropic import Anthropic
client = Anthropic(api_key=self.api_key)
system_message = None
messages = []
for message in history:
clean_message = {'role': message['role'], 'content': message['content']}View on GitHub (pinned to ae57a23577)
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.
Example fix
// before (config.ini for local provider) server_ip = localhost:9999 // after server_ip = localhost:8000 ; port where the OpenAI-compatible server actually listens
Defensive patterns
Strategy: type-guard
Validate before calling
import httpx
def assert_openai_compatible_endpoint(base_url, api_key, model, timeout=5):
r = httpx.post(
f"{base_url.rstrip('/')}/chat/completions",
headers={"Authorization": f"Bearer {api_key}"},
json={"model": model, "messages": [{"role": "user", "content": "ping"}], "max_tokens": 1},
timeout=timeout,
)
if not r.content.strip():
raise RuntimeError(f"Endpoint {base_url} returned an empty body for model {model}")
r.raise_for_status() Type guard
from types import SimpleNamespace
def is_valid_chat_completion(response) -> bool:
"""True only if the response has usable choices[0].message.content text."""
if response is None:
return False
choices = getattr(response, "choices", None)
if not choices:
return False
message = getattr(choices[0], "message", None)
return message is not None and isinstance(getattr(message, "content", None), str)
# usage
if not is_valid_chat_completion(response):
raise RuntimeError("OpenAI response is empty or malformed.") Try / catch
try:
thought = provider.openai_fn(history)
except Exception as e:
cause = e.__cause__
if "response is empty" in str(e).lower():
# local/compatible server returned empty body: check endpoint & model
raise RuntimeError(
"LLM endpoint returned an empty response; verify server_ip/base_url "
"and that the model is loaded."
) from cause
raise # propagate other API errors unchanged Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Anthropic response is empty.
- LM Studio returned empty response
- OpenRouter response is empty.
- MiniMax response is empty.
- OpenAI API error: {str(e)}
AI-assisted analysis of Fosowl/agenticSeek@ae57a23577 (2026-08-30).
Data as JSON: /api/errors/ce2dd9947f6a6e08.
Report an issue: GitHub.