Skip to content

flm serve crashes when a request is missing a required field (POST {}) #755

Open

Description

@noamsto

What happens

A request body that lacks a required field kills the flm serve process. No response is sent, and every later connection is refused until the server is restarted.

flm serve llama3.2:1b
curl -s -w '\nHTTP %{http_code}\n' http://127.0.0.1:52625/api/show \
  -H 'Content-Type: application/json' -d '{}'
# curl exit 56, HTTP 000; the flm process is gone
curl -s http://127.0.0.1:52625/v1/models
# connection refused

We saw the same crash with POST {} on /api/show, /api/generate and /v1/chat/completions, each tested in isolation. /api/chat and /v1/completions read their required field the same way, but we did not isolate them.

The same pattern explains a milder symptom. When /v1/embeddings gets no model, the handler happens to survive, and it answers HTTP 200 with {"error":"[json.exception.type_error.302] type must be string, but is invalid"}. The value it read was garbage, not a missing-key error.

Expected

A 400 naming the missing field, and the server keeps serving.

Cause

The handlers take const json& request and read required fields with operator[]:

  • handle_show: rest_handler.cpp:612 request["model"]
  • handle_generate: :650 request["prompt"]
  • handle_chat: :764 request["messages"]
  • handle_embeddings: :882-889 request["model"], request["input"]
  • handle_openai_chat_completion: :1103 request["messages"]
  • handle_openai_completion: :1410 request["prompt"]

On a const nlohmann::json, operator[] with a missing key is undefined behaviour. It is guarded only by JSON_ASSERT, which a release build compiles out, so it does not throw, and the surrounding try/catch never runs. The handler dereferences the map's end iterator instead.

Fix we are carrying

Check presence and type before each read, and refuse with a 400:
https://github.com/noamsto/nix-amd-ai/blob/46d7a73c1044435cec0ff08410e1a3bc87cbc544/pkgs/fastflowlm/patches/request-validation.patch

The require_field() helper is ported from OpenFlowLM-Next (src/server/openai_compat.hpp, Vegard Berget). Its error bodies carry an OpenAI-style string code ("missing_required_parameter"). Upstream send_response reads error.code with .get<int>() (server.cpp:736), which would throw on a string code. So the helper needs that line changed too. Our version of that change is in server-error-handling.patch in the same directory.

After the patch, all five endpoints answer POST {} with a 400 naming the field, and a normal chat request afterwards still completes. OpenFlowLM-Next's specs/server-api/tests/test_request_validation.py went from 0 of 22 passing to 14 passing with 8 skipped.

Environment

FLM v1.0.6 built from the tag, plus one downstream patch that only changes how send_response maps error.code to an HTTP status. That patch does not touch these read paths.
Ryzen AI MAX+ 395 (Strix Halo), XDNA2 NPU, 8 columns. NixOS, Linux 7.2.8, amdxdna 0.10, NPU FW 1.1.2.65. Model: llama3.2:1b.

We found this by running OpenFlowLM-Next's server-api conformance suite (specs/server-api/tests/, commit eb65600) against flm serve. Related but different trigger: #498.

Activity

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