Symptom
The Rust server converts every Axum JsonRejection into the same HTTP 400 invalid_body response. This changes status codes that clients use to distinguish an unsupported media type from an oversized request.
On current main:
| Request |
Expected |
Actual |
Valid JSON without Content-Type: application/json |
HTTP 415 |
HTTP 400 invalid_body |
| Body larger than the configured 32 MiB limit |
HTTP 413 |
HTTP 400 invalid_body |
Reproduction
Start the server with any valid route configuration:
switchyard-server --config routes.toml --host 127.0.0.1 --port 4000
Missing content type:
curl -sS -o response.json -w '%{http_code}\n' \
http://127.0.0.1:4000/v1/chat/completions \
--data '{"model":"noop-route","messages":[]}'
Observed:
400
{"error":{"code":"invalid_body","message":"Request body must be valid JSON: Expected request with `Content-Type: application/json`","type":"invalid_request_error"}}
Oversized body:
mkfile 33m oversized.bin
curl -sS -o response.json -w '%{http_code}\n' \
http://127.0.0.1:4000/v1/chat/completions \
-H 'Content-Type: application/json' \
--data-binary @oversized.bin
Observed:
400
{"error":{"code":"invalid_body","message":"Request body must be valid JSON: Failed to buffer the request body: length limit exceeded","type":"invalid_request_error"}}
Expected vs. actual
- Expected: Preserve the extractor rejection status: 415 for a missing JSON content type and 413 for a body over the configured limit. Anthropic requests should render the existing 413
request_too_large error type.
- Actual:
llm_json_body stringifies the rejection, then invalid_body_error always creates a 400 response. The server's explicit Anthropic mapping for StatusCode::PAYLOAD_TOO_LARGE is therefore unreachable for this extractor failure.
Environment
- Switchyard commit SHA:
b256d936f1d77bf13ec9bec399ea0a253e07ca05
- Rust version:
rustc 1.96.1 (31fca3adb 2026-06-26)
- OS / arch: macOS 26.5.2, arm64
- Install path: source checkout
- Inbound format: OpenAI Chat Completions; the same extractor path is shared by all three endpoints
- Backend: local
noop route; no provider credentials
Additional context
The relevant path is crates/switchyard-server/src/lib.rs: endpoint extractors return Result<Json<Value>, JsonRejection>, llm_json_body reduces an error to a string, and invalid_body_error hard-codes StatusCode::BAD_REQUEST.
I searched open and closed issues and pull requests for JSON extractor errors, length limit exceeded, missing content type 415, payload too large 413, and invalid_body status; I found no matching report or in-flight fix. PR #320 is related error-envelope work but does not preserve extractor status codes.
I'm happy to send a PR with focused 400/413/415 regression tests if this behavior should be preserved.
Symptom
The Rust server converts every Axum
JsonRejectioninto the same HTTP 400invalid_bodyresponse. This changes status codes that clients use to distinguish an unsupported media type from an oversized request.On current
main:Content-Type: application/jsoninvalid_bodyinvalid_bodyReproduction
Start the server with any valid route configuration:
Missing content type:
Observed:
Oversized body:
Observed:
Expected vs. actual
request_too_largeerror type.llm_json_bodystringifies the rejection, theninvalid_body_erroralways creates a 400 response. The server's explicit Anthropic mapping forStatusCode::PAYLOAD_TOO_LARGEis therefore unreachable for this extractor failure.Environment
b256d936f1d77bf13ec9bec399ea0a253e07ca05rustc 1.96.1 (31fca3adb 2026-06-26)nooproute; no provider credentialsAdditional context
The relevant path is
crates/switchyard-server/src/lib.rs: endpoint extractors returnResult<Json<Value>, JsonRejection>,llm_json_bodyreduces an error to a string, andinvalid_body_errorhard-codesStatusCode::BAD_REQUEST.I searched open and closed issues and pull requests for
JSON extractor errors,length limit exceeded,missing content type 415,payload too large 413, andinvalid_body status; I found no matching report or in-flight fix. PR #320 is related error-envelope work but does not preserve extractor status codes.I'm happy to send a PR with focused 400/413/415 regression tests if this behavior should be preserved.