Skip to content

Fix google ai empty stream body#563

Merged
brainlid merged 5 commits into
brainlid:mainfrom
nelsonkopliku:fix/google-ai-empty-stream-body
Jun 9, 2026
Merged

Fix google ai empty stream body#563
brainlid merged 5 commits into
brainlid:mainfrom
nelsonkopliku:fix/google-ai-empty-stream-body

Conversation

@nelsonkopliku

Copy link
Copy Markdown
Contributor

When a streaming request to Gemini returns 200 OK with zero delta chunks (e.g. immediate finish without content, or all chunks filtered by the SSE decoder), Req.Response.body stays as the binary default "" instead of the list of %MessageDelta{} the downstream code expects. Utils.handle_stream_fn/3 only converts "" to [] on the first {:data, ...} callback — if no callback fires, the conversion is skipped.

The body then reaches List.flatten(data) and crashes with FunctionClauseError on :lists.flatten(""), killing the upstream Task. Symptom in production:

** (FunctionClauseError) no function clause matching in :lists.flatten/1
   :lists.flatten("") at lists.erl:1145
   LangChain.ChatModels.ChatGoogleAI.do_api_request/3 at line 634

Add an is_list(data) guard to the existing 200 OK clause and a sibling clause that returns
{:error, %LangChainError{type: "empty_stream"}} for the zero-chunk case. The upstream chain already knows how to surface %LangChainError{} as a clean status change instead of crashing.

Regression test asserts the structured error is returned instead of the FunctionClauseError.

nelsonkopliku and others added 3 commits June 9, 2026 08:32
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
When a streaming request to Gemini returns 200 OK with zero delta
chunks (e.g. immediate finish without content, or all chunks filtered
by the SSE decoder), `Req.Response.body` stays as the binary default
`""` instead of the list of `%MessageDelta{}` the downstream code
expects. `Utils.handle_stream_fn/3` only converts `""` to `[]` on the
first `{:data, ...}` callback — if no callback fires, the conversion
is skipped.

The body then reaches `List.flatten(data)` and crashes with
`FunctionClauseError` on `:lists.flatten("")`, killing the upstream
Task. Symptom in production:

    ** (FunctionClauseError) no function clause matching in :lists.flatten/1
       :lists.flatten("") at lists.erl:1145
       LangChain.ChatModels.ChatGoogleAI.do_api_request/3 at line 634

Add an `is_list(data)` guard to the existing 200 OK clause and a
sibling clause that returns
`{:error, %LangChainError{type: "empty_stream"}}` for the zero-chunk
case. The upstream chain already knows how to surface
`%LangChainError{}` as a clean status change instead of crashing.

Regression test asserts the structured error is returned instead of
the FunctionClauseError.
Copilot AI review requested due to automatic review settings June 9, 2026 06:34

Copilot AI left a comment

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.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Adds a guard and structured error handling for Gemini streaming calls that return HTTP 200 but provide no streamed chunks, preventing a crash and validating the behavior with a regression test.

Changes:

  • Add a regression test for a streaming 200 response with an empty body to ensure a structured empty_stream error is returned.
  • Update the streaming response handling to only flatten list bodies, and return a LangChainError when the stream ends without deltas.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

File Description
test/chat_models/chat_google_ai_test.exs Adds a regression test covering the “200 + empty streaming body” scenario.
lib/chat_models/chat_google_ai.ex Adds guarded matching for streamed bodies and returns a structured empty_stream error instead of crashing.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread lib/chat_models/chat_google_ai.ex
Comment thread lib/chat_models/chat_google_ai.ex Outdated
Comment thread lib/chat_models/chat_google_ai.ex
Comment thread test/chat_models/chat_google_ai_test.exs
@nelsonkopliku nelsonkopliku requested a review from Copilot June 9, 2026 06:43

Copilot AI left a comment

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.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

Comment thread lib/chat_models/chat_google_ai.ex
@nelsonkopliku nelsonkopliku requested a review from Copilot June 9, 2026 06:50

Copilot AI left a comment

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.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

Comment thread lib/chat_models/chat_google_ai.ex
Comment thread lib/chat_models/chat_google_ai.ex
@brainlid

brainlid commented Jun 9, 2026

Copy link
Copy Markdown
Owner

Thanks @nelsonkopliku!
❤️💛💙💜

@brainlid brainlid merged commit ee65cd8 into brainlid:main Jun 9, 2026
2 checks passed
@nelsonkopliku nelsonkopliku deleted the fix/google-ai-empty-stream-body branch June 9, 2026 12:52
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.

3 participants