Fosowl/agenticSeek · error · Exception

Anthropic response is empty.

Error message

Anthropic response is empty.

What it means

Raised in anthropic_fn (sources/llm_provider.py:275) when client.messages.create() returns None instead of an Anthropic Message object. The library checks for None before accessing response.content[0].text and raises 'Anthropic response is empty.' to avoid a TypeError on the None response. Like the OpenAI path, it is immediately re-wrapped by the handler at line 281, so callers see 'Anthropic API error: Anthropic response is empty.'

Source

Thrown at sources/llm_provider.py:275

        client = Anthropic(api_key=self.api_key)
        system_message = None
        messages = []
        for message in history:
            clean_message = {'role': message['role'], 'content': message['content']}
            if message['role'] == 'system':
                system_message = message['content']
            else:
                messages.append(clean_message)

        try:
            response = client.messages.create(
                model=self.model,
                max_tokens=1024,
                messages=messages,
                system=system_message
            )
            if response is None:
                raise Exception("Anthropic response is empty.")
            thought = response.content[0].text
            if verbose:
                print(thought)
            return thought
        except Exception as e:
            raise Exception(f"Anthropic API error: {str(e)}") from e

    def google_fn(self, history, verbose=False):
        """
        Use google gemini to generate text.
        """
        base_url = self.server_ip
        if self.is_local:
            raise Exception("Google Gemini is not available for local use. Change config.ini")

        client = OpenAI(api_key=self.api_key, base_url="https://generativelanguage.googleapis.com/v1beta/openai/")
        try:
            response = client.chat.completions.create(

View on GitHub (pinned to ae57a23577)

Solutions

  1. Confirm the raw API works: curl https://api.anthropic.com/v1/messages with your key, model, and messages and inspect the JSON body.
  2. Check for proxies/gateways (HTTP_PROXY/HTTPS_PROXY, corporate middleboxes) that may return empty 200 responses; bypass them or fix their config.
  3. Upgrade the anthropic Python SDK so errors raise properly and responses deserialize correctly instead of yielding None.
  4. Verify the model name is a valid Anthropic model (e.g. claude-sonnet-4-20250514) and the API key is valid.
  5. If the error came from test code, fix the mock to return a realistic Message object rather than None.

Example fix

// before (test stub)
client.messages.create = lambda **kw: None

// after
client.messages.create = lambda **kw: SimpleNamespace(content=[SimpleNamespace(text='stub reply')])
Defensive patterns

Strategy: type-guard

Validate before calling

import os, httpx

def assert_anthropic_ready(api_key=None, model="claude-sonnet-4-20250514"):
    key = api_key or os.environ.get("ANTHROPIC_API_KEY")
    if not key:
        raise RuntimeError("ANTHROPIC_API_KEY is not set")
    r = httpx.post(
        "https://api.anthropic.com/v1/messages",
        headers={"x-api-key": key, "anthropic-version": "2023-06-01"},
        json={"model": model, "max_tokens": 1, "messages": [{"role": "user", "content": "hi"}]},
        timeout=10,
    )
    if r.status_code == 401:
        raise RuntimeError("Anthropic API key is invalid")
    if not r.content.strip():
        raise RuntimeError("Anthropic endpoint returned an empty body (check proxies)")
    r.raise_for_status()

Type guard

def is_valid_anthropic_message(response) -> bool:
    """True only if the response has accessible content[0].text."""
    if response is None:
        return False
    content = getattr(response, "content", None)
    if not content:
        return False
    return isinstance(getattr(content[0], "text", None), str)

# usage
if not is_valid_anthropic_message(response):
    raise RuntimeError("Anthropic response is empty or malformed.")

Try / catch

import time

def anthropic_fn_with_retry(provider, history, retries=3):
    try:
        return provider.anthropic_fn(history)
    except Exception as e:
        cause = e.__cause__
        if "response is empty" in str(e).lower():
            raise RuntimeError(
                "Anthropic returned an empty response; check proxies/gateway "
                "and anthropic SDK version."
            ) from cause
        if "429" in str(e) or "overloaded" in str(e).lower():
            time.sleep(2 ** retries)
            return provider.anthropic_fn(history)
        raise

Prevention

When it happens

Trigger: client.messages.create(model=self.model, max_tokens=1024, messages=messages, system=system_message) returns None — most plausible with a proxy/gateway or non-standard base URL returning an empty 200 body, or an SDK/server deserialization mismatch. Note this is the only non-message role filtering path: system messages are extracted into system_message before the call.

Common situations: Corporate proxy or API gateway intercepting requests and returning empty bodies; monkeypatched or outdated anthropic SDK returning None on error instead of raising; response stubs/mocks returning None in tests wired to real code; hitting a wrong base_url that responds 200 with empty content.

Related errors


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