Skip to content

fix: guard LLM response access in 39 cookbook examples - #138

Open
qizwiz wants to merge 1 commit into
The-Pocket:mainfrom
qizwiz:fix/llm-response-unguarded
Open

fix: guard LLM response access in 39 cookbook examples#138
qizwiz wants to merge 1 commit into
The-Pocket:mainfrom
qizwiz:fix/llm-response-unguarded

Conversation

@qizwiz

@qizwiz qizwiz commented May 18, 2026

Copy link
Copy Markdown

Summary

response.choices[0].message.content is typed Optional[str] in the OpenAI SDK — it returns None (not raises) when the provider applies content filtering or when finish_reason is "tool_calls". Every unguarded .content access in the cookbook is a latent crash site.

This PR adds a uniform three-layer guard before every unguarded access across all 39 cookbook utility files:

if not r.choices or r.choices[0].message is None or r.choices[0].message.content is None:
    raise ValueError("LLM returned empty or filtered response")
return r.choices[0].message.content

Anthropic calls are guarded analogously (len(response.content) == 0 / .text is None).

Files changed: all cookbook/*/utils.py and cookbook/*/utils/call_llm.py files — 39 files, 138 insertions.

Why this matters

The OpenAI SDK types ChatCompletionMessage.content as Optional[str]. The silent None return propagates downstream — the crash happens far from the API call, often in user-facing code, with a confusing TypeError: argument of type 'NoneType' is not iterable or similar message.

Test plan

  • Verify each patched call_llm raises ValueError when given a mock response.choices = []
  • Smoke-test one example end-to-end to confirm guard doesn't fire on normal response

🤖 Generated with Claude Code

response.choices[0].message.content is Optional[str] — returns None when
the provider applies content filtering or the response consists entirely
of tool calls (finish_reason="tool_calls"). Accessing .content without a
guard raises AttributeError or propagates None silently.

Adds a uniform check before every unguarded .content access across all
cookbook utility files:

    if not r.choices or r.choices[0].message is None or r.choices[0].message.content is None:
        raise ValueError("LLM returned empty or filtered response")

Anthropic calls guarded analogously: len(response.content) == 0 or
response.content[0].text is None.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant