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

  1. Verify the endpoint actually serves the model: curl the /v1/chat/completions route with the same model name and inspect the raw JSON body.
  2. 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.
  3. Confirm the model name exists on the endpoint (list models via GET /v1/models); a wrong model can make some servers return empty responses.
  4. Upgrade the openai Python SDK so response parsing matches the server's response format.
  5. 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

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


AI-assisted analysis of Fosowl/agenticSeek@ae57a23577 (2026-08-30). Data as JSON: /api/errors/ce2dd9947f6a6e08. Report an issue: GitHub.