Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

parseStreamChatResponse ignores the [DONE] sentinel and hangs until read timeout on keep-alive servers

Open Beginner friendly
#446 0 comments 0 reactions 0 assignees View on GitHub

@mikemikimike is already working on this.

Since Oct 19, 2026.

  • #447 by @mikemikimike — open

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
84/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
php
Domain
backend

Research direction

Start with lib/Service/StreamingService.php, especially parseStreamChatResponse() around line 51 and parseSseEvent() around lines 114–116, where the issue says the [DONE] state is detected. Check for existing streaming service tests and run the relevant test; the issue does not name a test file. Done means the generator returns after [DONE] without waiting for the keep-alive connection to close, while preserving any final usage chunk.

Written by the indexing model from the issue text.

Description

bug
Which version of integration_openai are you using?

5.0.0

Which version of Nextcloud are you using?

35.0.2

Which browser are you using? In case you are using the phone App, specify the Android or iOS version and device please.

Firefox 158.0

Describe the Bug

When streaming chat completions against a self-hosted OpenAI-compatible server that responds with:
Content-Type: text/event-stream,
Connection: keep-alive
and a correct data: [DONE] terminator, the stream is parsed fine (partial output appears in the UI) but never terminates.

After data: [DONE], the read loop in StreamingService::parseStreamChatResponse() (lib/Service/StreamingService.php:51) keeps calling fread() until the connection itself closes — which a keep-alive server does not do.

The generator stalls for the full service request timeout (Application::OPENAI_DEFAULT_REQUEST_TIMEOUT = 60 × 4 s), then fread() fails at StreamingService.php:54 and throws:

TaskProcessing core:text2text:multimodal-chatwithtools task failed: OpenAI/LocalAI request failed: Malformed API response

The loop already tracks end of stream correctly: parseSseEvent() sets $done = true when it parses data: [DONE] (line 114–116), but the while (!feof($body)) loop condition never consults $done. So stream completion is detected and then ignored, and "connection closed" is used as the stream-end signal. api.openai.com masks the bug because it closes the connection immediately after [DONE], so feof() arrives right behind the sentinel. Verified with curl that the server side is spec-clean: valid LF-framed SSE, valid JSON events, finish_reason + [DONE], proper chunked-transfer termination, Connection: keep-alive response header.

The systemd nextcloud-ai-worker is blocked for the 4 minute timeout period.

Proposed fix: change the loop condition to while (!$done && !feof($body)) (line 51) and fclose($body) once done, instead of waiting for a TCP close that compliant HTTP/1.1 servers have no obligation to send.

I added just the !$done and observed correct behavior in Assistant chats.

Expected Behavior

The generator should return immediately after parsing data: [DONE] (or a finish_reason event), regardless of whether the server keeps the TCP connection alive. The TaskProcessing task should complete with the full streamed result within the normal generation time, quota usage should be recorded from the final usage chunk if present, and no "Malformed API response" error should be raised. A keep-alive connection that stays open after a correctly terminated chunked body is compliant HTTP/1.1 and must not stall the client.

To Reproduce

Point a service at any OpenAI-compatible endpoint that streams SSE with keep-alive (this repro: self-hosted DGPP inference server, model nvidia/Qwen3.8-Flash-Next-NVFP4, Transfer-Encoding: chunked, Connection: keep-alive).

Confirm the stream itself is well-formed and finishes promptly with curl:

BASE_URL='http://<hostname>/v1'
MODEL='your/model'
KEY='APIKey'
curl -v -N "$BASE_URL/chat/completions" -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" -d '{"model":"'"$MODEL"'","messages":[{"role":"user","content":"hi"}],"stream":true,"n":1}'

curl receives deltas, data: [DONE] and exits within seconds; response headers show Content-Type: text/event-stream and Connection: keep-alive, and curl reports the connection left intact.

In Nextcloud, trigger a streaming TaskProcessing task against the same service (e.g. core:text2text:multimodal-chatwithtools, preferStreaming: true). I typed "Hi" in Nextcloud assistant "Chat with AI".

Observe: output streams normally at first (might just be reasoning), then the task eventually fails with OpenAI/LocalAI request failed: Malformed API response — after ~4 min. For larger complex prompts the UI shows a complete-looking answer, then the same error. The delay equals the service request timeout (default 240 s = 60 × 4, AppInfo/Application.php:24).

Dominant language
PHP
Stars
76
Forks
34
Avg merge
4d 54m
Merged PRs (30d)
2

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from nextcloud/integration_openai

All issues in nextcloud/integration_openai

Similar issues

More PHP issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.