Pull requests / #2563
#2563 serve: a number json reads as infinite, or nesting deeper than Python recurses, is a 400 instead of a dropped connection
open · @qiuzan2001 · 0 Kommentare · Auf GitHub
Beschreibung
**What it changes.** Python's `json` reads `Infinity`, `-Infinity`, `NaN` and `1e400` (as an infinite float) and nests as deep as its recursion limit allows. Some of those requests got no HTTP answer at all: the connection closed and a traceback went to the log. - `POST /v1/chat/completions` / `/v1/messages` with `"max_tokens"` or `"max_completion_tokens"` of `Infinity`, `-Infinity` or `1e400`: `int()` raised `OverflowError`, which no `except` in `_post` took. - A body nested past `json`'s limit (100,000 levels), or a tool's `parameters` schema 600 levels deep (the server's own walk of it): `RecursionError`, same result. - `POST /config` (the Settings view's keys): `reasoning_budget_tokens: Infinity` and a 400-digit whole number for `sampling.temperature` (`float()` overflows) dropped the connection the same way, and `Infinity` for `idle_unload_s`, `engine_silence_s` or `sampling.temperature` was accepted and written into the run config as `Infinity`, which is not JSON that other programs (editors, `jq`) read. Now `OverflowError` and `RecursionError` join the existing malformed-request 400 (`TypeError`, `KeyError`, ... "the request is malformed (...)", traceback in the log; a `RecursionError` logs its last 8 frames instead of ~1,000, ~240 KB per request before). `runconfig._number` refuses a float that is not finite (a 400 naming the key), and `_config_post` answers an `OverflowError` with 400. A huge *whole* number for `idle_unload_s` is still taken, as before. **What it leaves alone.** Every request that got an answer before gets the same answer: the new `except` entries only catch what used to escape to the socket server, and an error after the answer began is still re-raised as before. The web app cannot send these values (`JSON.stringify(Infinity)` is `null`). Needs the API key where one is set, like any request. **How it was checked.** New tests, each failing before the change: `test_request_hardening.Hardening.test_an_infinite_number_is_400` (9 cases), `test_a_too_deeply_nested_body_is_400` (600 and 100,000 levels), `test_runconfig.Apply.test_refused` (non-finite values for 8 keys, and a huge whole number still taken), `test_runconfig.Http.test_a_number_too_big_or_not_finite_is_400`. The whole `serve` suite passes on the final commit (788 tests) except `test_keepawake.test_service_holds_for_the_whole_request_including_early_close`, which fails the same way on `main` on this Linux box (Ubuntu, Python 3.14). A sub-agent reviewer fuzzed 1e400 and a 400-digit integer into ~22 numeric fields on 10 routes: no dropped connection after the change. Found in a security read of `serve/server.py` (#544's invitation). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Mehr auf der Site
Links zu Install, Modellen, Releases.