fix: guard against empty/filtered LLM responses in get_first_message_content#524
fix: guard against empty/filtered LLM responses in get_first_message_content#524qizwiz wants to merge 2 commits into
Conversation
…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.
There was a problem hiding this comment.
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.
| if not completion.choices or completion.choices[0].message is None: | ||
| raise ValueError("LLM returned empty or filtered response") |
There was a problem hiding this comment.
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.
| 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") |
| if not completion.choices or completion.choices[0].message is None: | ||
| raise ValueError("LLM returned empty or filtered response") |
There was a problem hiding this comment.
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.
| 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") |
…tent message.content can be None when the model returns a tool call or when content is filtered (HTTP 200 with null content field). Without this check the function silently returns None instead of raising ValueError. Addresses Gemini code review feedback on PR AsyncFuncAI#524.
What
Add null checks in
api/openai_client.pyandapi/azureai_client.pybefore accessingchoices[0].message.contentinget_first_message_content.Why
Two crash vectors exist:
IndexError— whenchoicesis empty (network interruption, provider edge cases returning HTTP 200 with empty body)AttributeError— whenchoices[0].messageisNone. Observed on Gemini via OpenAI-compatible endpoint on PROHIBITED_CONTENT (HTTP 200 withmessage: null)Fix
No behaviour change for well-formed responses.