fix(ch06): guard against IndexError on empty LLM choices list#1221
fix(ch06): guard against IndexError on empty LLM choices list#1221qizwiz wants to merge 2 commits into
Conversation
Nine example scripts in chapter 06 access choices[0] without checking whether the API returned any choices. Content-policy filters, token limits, and non-standard responses can all return choices=[]. - aoai-app.py, aoai-history-bot.py, aoai-study-buddy.py: wrap print in `if completion.choices` - oai-app.py, oai-history-bot.py, oai-study-buddy.py: same - githubmodels-app.py: wrap print in `if response.choices` - aoai-app-recipe.py, oai-app-recipe.py: guard both choices accesses and skip the dependent shopping-list call when first response is empty
|
👋 Thanks for contributing @qizwiz! We will review the pull request and get back to you soon. |
…content-filter) Gemini 2.5 Flash returns HTTP 200 with choices[0].message=None when content is filtered, causing AttributeError even when choices is non-empty. Extends all 9 app guards to also check `message is not None` / `message is None`.
|
Update: extended guards to cover Gemini content-filter crash path Testing against live providers found that Gemini 2.5 Flash returns HTTP 200 with Pushed follow-up commit (05bd9ac) extending all 9 app files to the comprehensive guard: if completion.choices and completion.choices[0].message is not None:
print(completion.choices[0].message.content)This covers both crash vectors in a single check. |
|
Quick status summary for reviewers: This PR guards against two distinct crash paths in the chapter 06 tutorial scripts:
Both are real failure modes learners will hit when running these examples against live APIs. The guards are minimal and don't change the tutorial logic — they just print a friendly message instead of crashing. |
Problem
Nine example scripts in chapter 06 call
choices[0].message.contentwithout checking whether the API returned any choices. This raises a bareIndexErrorwhen:choices=[]These are tutorial scripts that learners copy and run — an
IndexErrorhere is confusing and makes the example look broken.Changes
aoai-app.pyif completion.choices:before printingaoai-history-bot.pyaoai-study-buddy.pyoai-app.pyoai-history-bot.pyoai-study-buddy.pygithubmodels-app.pyif response.choices:before printingaoai-app-recipe.pychoicesaccesses; skip dependent shopping-list call when first response is emptyoai-app-recipe.pyAll changes are minimal defensive checks — no logic changes for successful API responses.
Found by pact static analysis —
llm_response_unguardedmode.