Skip to content

fix: unblock long-context requests in the rust router, and kvd bug - #120

Merged
jiejingzhangamd merged 3 commits into
mainfrom
dev/xiaobo/815
Aug 15, 2026
Merged

fix: unblock long-context requests in the rust router, and kvd bug#120
jiejingzhangamd merged 3 commits into
mainfrom
dev/xiaobo/815

Conversation

@xiaobochen-amd

Copy link
Copy Markdown
Collaborator

Description

Two independent fixes found while running GLM-5.2 1P1D agentic on MI355X.
Measurements are in the per-commit messages.

Type of change

  • Bug fix (non-breaking change which fixes an issue)

Changes

  • The rust router 413s any body over 2 MiB. The Bytes extractors in
    handlers.rs inherit axum's default limit, so a long-context prompt never
    reaches the engine: 26 of the 27 dropped requests in a 3600s agentic run, and
    an outright warmup abort at concurrency 64. The engine accepts 3 MiB and so
    does this router's own python backend, so the two backends disagreed on what a
    legal request is. Disabled rather than raised — prompt size is the engine's
    --context-length to enforce, not a proxy's. Regression test included.

  • A kvd leg dies at startup on the v0.5.17 base. ServerArgs.__setattr__
    now refuses public writes after resolution unconditionally, where it used to
    be gated on SGLANG_STRICT_CONFIG_MUTATION, and _finish_wiring's first
    assignment raises. Those writes are metadata-only — the engine subprocess
    re-parses argv — so they are best-effort now.

Checklist:

  • The functionality is complete
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes

cargo fmt, clippy --all-targets -- -D warnings and cargo test -p infera-router are clean; the regression test reproduces the 413 with the layer
removed. Verified on a live deployment: a 3.00 MiB body now comes back as the
engine's 400 instead of 413.

The kvd path is not exercised by deployments that run without
--infera-kvb-socket, so that fix is reasoned rather than measured.

xiaobochen-amd and others added 2 commits August 15, 2026 13:21
The rust router 413s any request whose body exceeds 2 MiB, so a long-context
prompt never reaches the engine. In the 8-14 GLM-5.2 agentic run this was 26 of
the 27 dropped requests, reported by the aggregation as

  "error_categories": {"InvalidInferenceResultError": 1, "Payload Too Large": 26}

and at concurrency 64 it aborted warmup outright.

handlers.rs takes the body with the `Bytes` extractor, which inherits axum's
DefaultBodyLimit of 2 MiB. Nothing in the router configures it -- there is no
DefaultBodyLimit, body_limit or RequestBodyLimitLayer anywhere in rust/router.
A web-form default is the wrong ceiling for an LLM proxy, where a prompt near
the engine's context length is several MiB of JSON.

Measured against a live 1P1D deployment (GLM-5.2-MXFP4, TP8 per leg):

| body     | rust :8100 | python :8101 | engine :30000 |
|----------|------------|--------------|---------------|
| 2.00 MiB | 200        |              |               |
| 2.05 MiB | 413        |              |               |
| 3.00 MiB | 413        | 400          | 400           |

The 400 is the engine rejecting the body's contents, which means the body
arrived. So the engine accepts 3 MiB and so does this router's own python
backend: Starlette imposes no body limit and nothing in infera/server/ or
infera/api/ adds one. Only the rust backend refused it, and it is the default
backend, so the two backends of the same router disagreed on what is a legal
request.

Disable the limit rather than raising it. Any number here is arbitrary and will
be wrong for someone; the ceiling on prompt size is the engine's
--context-length, and a proxy has no business imposing a second, smaller one.
This also makes the two backends agree.

functional.rs gets a regression case that posts a 4 MiB prompt through the
assembled app and asserts the mock worker received it whole. With the layer
commented out it reproduces the production failure exactly (left: 413,
right: 200). The mock worker needs the same disable, since it stands in for an
engine that caps a prompt by context length rather than by request bytes.

cargo fmt, clippy --all-targets -- -D warnings and the full
cargo test -p infera-router suite (134 unit + 15 functional) are clean.
Verified on the deployment afterwards: a 3.00 MiB body uploads all 3,145,765
bytes and comes back 400 from the engine's field validation instead of 413.

Signed-off-by: xiaobochen-amd <xiaobo.chen@amd.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
… write

A kvd prefill leg died at startup on lmsysorg/sglang:v0.5.17-rocm720-mi35x, on
the first assignment _finish_wiring makes:

  sa.enable_hierarchical_cache = True

ServerArgs.__setattr__ raises AttributeError for any public field assigned after
resolution -- "server_args.<name> assigned after resolution; server_args is
read-only -- use get_context().override(source, ...)". The guard is not new; on
this base it is unconditional where it used to be gated on
SGLANG_STRICT_CONFIG_MUTATION, so wiring that worked before now raises.
ServerArgs is not a frozen dataclass (__dataclass_params__.frozen is False), so
the failure is that custom __setattr__ rather than dataclass immutability.

Every write in _finish_wiring is metadata-only. The engine runs in a subprocess
that re-parses argv, and _append_sglang_hicache_argv is what actually selects
the backend, so these assignments only keep the in-process record tidy. Losing
one must not cost a leg. Make each best-effort, log the refusal at debug, and
emit the "implies ..." info line only when the value landed -- otherwise the log
claims a sync that did not happen.

Not exercised by the 1P1D agentic deployments in use: they run without
--infera-kvd-socket and so never enter this function. The change is confined to
that path.

Signed-off-by: xiaobochen-amd <xiaobo.chen@amd.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Copilot AI lite review requested due to automatic review settings August 15, 2026 13:25

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR contains two independent bug fixes: (1) removing an unintended 2 MiB request-body cap in the Rust router that was 413’ing long-context prompts before they reached the engine, and (2) making SGLang KVD wiring metadata updates best-effort to avoid startup failure on the v0.5.17 base where ServerArgs becomes read-only after resolution.

Changes:

  • Disable axum’s default request body limit on the Rust router so long-context requests are forwarded to the engine instead of being rejected at the proxy.
  • Add a functional regression test ensuring the router forwards a request body larger than axum’s default limit.
  • Make KVD wiring’s ServerArgs metadata mutations resilient to AttributeError (read-only ServerArgs) so KVD legs don’t crash at startup.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
rust/router/src/handlers.rs Disables axum default body limit for Bytes request bodies so long-context prompts aren’t rejected by the router.
rust/router/tests/functional.rs Adds a regression test that sends an over-2 MiB request body and asserts it reaches the upstream worker.
infera/engine/sglang/kvd_wiring.py Wraps ServerArgs metadata writes in a best-effort helper to avoid startup aborts on read-only configurations.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread rust/router/src/handlers.rs Outdated
Comment thread rust/router/tests/functional.rs Outdated
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@jiejingzhangamd
jiejingzhangamd merged commit ac35394 into main Aug 15, 2026
2 of 4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants