Skip to content

flm serve: /v1/completions, /api/generate and /api/chat keep decoding after the client disconnects #760

Open

Description

@noamsto

Everything below comes from reading the source on main at 39ff855. None of it has been measured.

What looks wrong

The server creates a CancellationToken for every request. The token is cancelled when the client socket closes (server.cpp:357-388) or when /api/cancel is called. /v1/chat/completions uses it: it calls cancellation_token->reset() and passes [&] { return cancellation_token->cancelled(); } to both insert() and generate() (rest_handler.cpp:1194-1236, :1257-1288).

The other generation routes accept the token and never read it:

So if a client drops mid-request on one of these routes, the server should keep decoding to max_tokens / num_predict (default 4096). For /api/generate and /api/chat, that also holds the NPU lock and blocks the queue behind it. /v1/completions isn't queued at all (see #759). /api/cancel has no effect on these routes for the same reason.

Expected

Cancelling on disconnect behaves the same on every generation route as it does on /v1/chat/completions.

Suggested fix

In each of these handlers, call cancellation_token->reset() and pass the same [&] { return cancellation_token->cancelled(); } predicate to insert() and generate(), as handle_openai_chat_completion does. Non-streaming /api/chat would need either a predicate on generate_with_prompt() or a switch to insert() + generate(). The second option changes output for Qwen3.5, Qwen3.6-MoE and GPT-OSS, whose generate_with_prompt() differs from that pair.

A probe that closes the connection mid-stream should confirm it: eval_count in the log stops short, and NPU Lock Released! follows promptly. We haven't run it yet.

Environment

Found by reading the source; checked against main at 39ff855 and v1.0.6.

Related, but a different resource: #680, where client aborts leak connection slots.

Activity

  1. Bla2020yt commented on Sep 28, 2026

    @Bla2020yt

    I can agree with that (VS Code with Roo Code MCP).

    It also happens with the Lemonade FLM backend.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions