#457

fix: guard against empty/filtered LLM responses in legacy LLM models

Openqizwizwants to merge intofrom

What

Adds null checks before accessing choices[0].message in five files under legacy/pentestgpt/:

  • llm_generation/models/open_ai.py
  • llm_generation/models/deepseek.py
  • llm_generation/models/jina.py
  • utils/APIs/chatgpt_api.py
  • utils/APIs/deepseek_api.py

Why

Two silent failure modes crash at these lines:

  1. IndexError — choices is an empty list ([]) when the provider returns no completions
  2. AttributeError — choices[0].message is None when content is filtered (some providers return HTTP 200 with PROHIBITED_CONTENT finish reason)

Fix

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

Detected by pact static analysis.

Activity

9
gemini-code-assist[bot]reviewed5mo ago
gemini-code-assist[bot]5mo ago

Code Review

This pull request adds validation logic to ensure LLM responses are not empty or filtered before processing them across several files. However, the implementation in chatgpt_api.py and deepseek_api.py contains critical syntax errors because if and raise statements were placed directly inside class constructor arguments. Additionally, these checks are positioned after the response data is already accessed, which would cause a crash before the validation logic is executed. These checks should be moved to the start of the methods.

qizwiz5mo ago

Thanks @gemini-code-assist — you're right, the guard was incorrectly placed inside the InitialGeneration(...) constructor argument list in both chatgpt_api.py and deepseek_api.py, which is invalid Python syntax.

Fixed in commit 88d021a: moved the guard before the langfuse block in both files, so it runs as a standalone statement before any constructor is called. The now-redundant second guard after the langfuse block was removed. Syntax verified with ast.parse().

gemini-code-assist[bot]5mo ago

Thanks for the update, @qizwiz. Moving the guard before the langfuse block is the correct approach to ensure the response is validated before any downstream processing or logging occurs. This effectively prevents potential AttributeError or IndexError exceptions and keeps the logic clean. The fix looks solid.

qizwiz5mo ago

Thanks for the review! A quick clarification on the placement concern:

The guard at lines 138–142 is outside the InitialGeneration(...) constructor call — it's an if statement at function body scope that executes before the langfuse block begins. If choices is empty or message is None, ValueError is raised immediately and lines 146–158 are never reached. Both files pass ast.parse cleanly (no SyntaxError).

That said, your point about message.content being None is valid — I've just pushed an update that extends the guard to also cover message.content is None, which can occur for tool-call responses or filtered content. The langfuse completion= parameter will now never receive None.

qizwiz5mo ago

The syntax issue was fixed in 88d021a (guard moved before the langfuse block). The current HEAD (d274d06) passes ast.parse cleanly on both files — the guard is at function-body scope, not inside any constructor argument. Happy to address any remaining concerns once the review reflects the current diff.

aegisforensicsmonkapproved changes5mo ago