Skip to content

fix: guard against empty choices and message=None in LLM client#26

Merged
adaamko merged 1 commit into
KRLabsOrg:mainfrom
qizwiz:fix/guard-llm-response-choices
May 31, 2026
Merged

fix: guard against empty choices and message=None in LLM client#26
adaamko merged 1 commit into
KRLabsOrg:mainfrom
qizwiz:fix/guard-llm-response-choices

Conversation

@qizwiz
Copy link
Copy Markdown
Contributor

@qizwiz qizwiz commented May 18, 2026

What

Add guards in LLMClient.complete() and LLMClient.complete_async() before accessing response.choices[0].message.content.

Why

chat.completions.create() can return two empty-response shapes, both unhandled:

  1. choices = [] — on content-policy rejections, rate-limit errors, or provider failures
  2. choices[0].message = None — Gemini 2.5 Flash (via the OpenAI-compatible endpoint) returns HTTP 200 with finish_reason: PROHIBITED_CONTENT and message=None rather than raising an exception

Both crash with IndexError or AttributeError. For a hallucination-prevention RAG system that may query multiple providers, silent crashes degrade the reliability guarantees the library is designed to provide.

Change

# Before
return response.choices[0].message.content

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

Applied to both complete() (sync) and complete_async() (async).

Corpus context

Detected by pact (llm_response_unguarded mode), a Z3-verified static analyzer for LLM crash vectors. This pattern was found across 13.7k violations in 786 repos.

chat.completions.create() can return choices=[] (content-policy
rejections, provider errors) or choices[0].message=None (e.g. Gemini
PROHIBITED_CONTENT via OpenAI-compatible endpoint, HTTP 200). Both crash
with IndexError/AttributeError. Guards added to both sync complete()
and async complete_async() paths.
@adaamko adaamko self-requested a review May 31, 2026 20:03
@adaamko adaamko merged commit 0332f8e into KRLabsOrg:main May 31, 2026
5 checks passed
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.

2 participants