Skip to content

fix: guard against empty/filtered LLM responses in get_first_message_content#524

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

fix: guard against empty/filtered LLM responses in get_first_message_content#524
qizwiz wants to merge 1 commit into
AsyncFuncAI:mainfrom
qizwiz:fix/llm-response-unguarded

Conversation

@qizwiz
Copy link
Copy Markdown

@qizwiz qizwiz commented May 18, 2026

What

Add null checks in api/openai_client.py and api/azureai_client.py before accessing choices[0].message.content in get_first_message_content.

Why

Two crash vectors exist:

  1. IndexError — when choices is empty (network interruption, provider edge cases returning HTTP 200 with empty body)
  2. AttributeError — when choices[0].message is None. Observed on Gemini via OpenAI-compatible endpoint on PROHIBITED_CONTENT (HTTP 200 with message: null)

Fix

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

No behaviour change for well-formed responses.

…content

Add null checks in openai_client.py and azureai_client.py before
accessing choices[0].message.content. Empty choices causes IndexError;
None message (some providers on filtered content with HTTP 200) causes
AttributeError.
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces validation checks in the get_first_message_content function for both Azure and OpenAI clients to handle empty or null responses from the LLM. The reviewer recommended extending these checks to include a validation for message.content being None. This ensures the function consistently returns a string as per its type hint, preventing potential errors when responses are filtered or contain non-textual data.

Comment thread api/azureai_client.py
Comment on lines +78 to +79
if not completion.choices or completion.choices[0].message is None:
raise ValueError("LLM returned empty or filtered response")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The check should also include a validation for completion.choices[0].message.content. In some scenarios (such as content filtering or when the model returns a tool call instead of text), the message object might exist but its content field can be None. Since this function is type-hinted to return a str, returning None would violate the contract and likely cause errors in downstream components that expect a string. Adding this check ensures that we only proceed when actual text content is available.

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

Comment thread api/openai_client.py
Comment on lines +62 to +63
if not completion.choices or completion.choices[0].message is None:
raise ValueError("LLM returned empty or filtered response")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Similar to the Azure client, the check here should also validate that completion.choices[0].message.content is not None. This prevents the function from returning None when a str is expected, which can happen if the response is filtered or contains non-textual data. This is especially important given the PR's goal of guarding against "filtered" responses.

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

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