Skip to content

[bug] llm/openai_compatible: streaming request has no timeout waiting for response headers — a stalled optional-API backend wedges chat forever #938

Description

@kurosawareiji7007-hub

Bug

OpenAiCompatibleBackend::post_chat (crates/genie-core/src/llm/openai_compatible.rs) sets request.timeout(...) only on the non-streaming branch. For streaming it only adds Accept: text/event-stream, then awaits request.send() with no deadline.

The reqwest::Client is built with connect_timeout only. Once TCP is up, send().await waits forever for response headers. Per-chunk timeouts.read in chat_stream_once only applies after headers arrive.

A backend that accepts the connection but stalls before the first response byte hangs the stream task. POST /api/chat/stream holds the single-slot ChatTurnGate, so other chat requests stay busy until process restart.

The sibling raw-TCP local client (openai_compat.rs) already bounds the status-line wait; this reqwest optional-API path does not.

Expected

Waiting for streaming response headers should hit timeouts.read (or equivalent) and fail closed.

Actual

send().await parks until the peer closes or headers arrive — no idle deadline.

Suggested fix

Wrap streaming request.send() in tokio::time::timeout(self.timeouts.read, ...) (do not put a reqwest whole-request timeout on the stream — that would kill long SSE bodies). Map elapsed to a clear timeout error.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions