Skip to content

fix(frontend): return JSON errors for invalid content types and unknown routes - #13102

Merged
rmccorm4 merged 12 commits into
mainfrom
spolisetty/dis-2541-a4-malformed-non-json-http-response-body
Aug 18, 2026
Merged

rmccorm4 merged 12 commits into
mainfrom
spolisetty/dis-2541-a4-malformed-non-json-http-response-body

Conversation

@pskiran1

@pskiran1 pskiran1 commented Aug 12, 2026 •

Copy link
Copy Markdown
Contributor

Overview:

This PR fixes non-JSON error responses on the OpenAI-compatible HTTP API. OpenAI clients expect error responses to use a JSON error envelope. Previously, some invalid requests returned plain-text or empty responses.

This PR returns the standard {"message", "type", "code"} error envelope for:

  • Invalid or missing JSON Content-Type headers on POST /v1/responses
  • Unmatched routes, including GET /v1/responses/{response_id}

Details:

Responses request parsing

handler_responses previously used Axum's Json<T> extractor. Because extractors run before the handler, invalid or missing JSON content types were rejected by Axum with a plain-text 415 Unsupported Media Type response. The handler now reads the request body directly and uses the existing ensure_json_content_type and parse_json_request helpers, consistent with the Chat Completions and Completions handlers.

Unmatched routes

Added unmatched_route_fallback to return a JSON 404 response when no registered route matches the request path. The fallback is registered after routers are merged, since Axum permits only one custom fallback, and before service layers are applied so fallback responses include the same request-level behavior, such as x-request-id. Existing handler-level errors, such as Model not found, are unchanged.

Validation

Added tests:

  • test_responses_non_json_content_type_returns_json_error
  • test_responses_malformed_json_returns_json_error
  • test_unknown_response_id_returns_json_404
  • test_unknown_path_returns_json_404

Manual verification against a frontend serving Qwen/Qwen3.5-4B:

Request Before After
POST /v1/responses with Content-Type: text/plain 415 with plain-text body 415 with JSON error envelope
POST /v1/responses without Content-Type 415 with plain-text body 415 with JSON error envelope
POST /v1/responses with malformed JSON Raw Axum error response 400 with JSON error envelope
GET /v1/responses/resp_x 404 with empty body 404 with JSON error envelope
GET /v1/not_a_route 404 with empty body 404 with JSON error envelope

Regression checks:

Request Expected result
POST /v1/responses with application/json; charset=utf-8 Request parsing succeeds
POST /v1/chat/completions with an unknown model Existing Model not found response
GET /v1/models and GET /health 200 responses unchanged
GET /metrics Prometheus text response unchanged
GET /v1/responses Existing 405 response with Allow: POST unchanged

Related Issues

⚠️ This section is required. Choose one path below and delete the other.

🔗 This PR is linked to an issue:

🚫 This PR is NOT linked to an issue:

  • Confirmed — no related issue

Summary by CodeRabbit

  • Bug Fixes
    • Improved handling of response requests with clearer validation for content types and malformed request data.
    • Added consistent, OpenAI-compatible JSON error responses for unsupported media types, invalid bodies, unknown response IDs, and unavailable paths.
    • Error responses now include the relevant request method and path when a route cannot be found.
  • Tests
    • Added coverage for request validation and standardized error responses.

Signed-off-by: Sai Kiran Polisetty <spolisetty@nvidia.com>
@copy-pr-bot

copy-pr-bot Bot commented Aug 12, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@github-actions github-actions Bot added fix frontend `python -m dynamo.frontend` and `dynamo-run in=http|text|grpc` labels Aug 12, 2026
@pskiran1
pskiran1 requested a review from rmccorm4 August 12, 2026 15:17
@pskiran1
pskiran1 marked this pull request as ready for review August 12, 2026 15:17
@pskiran1
pskiran1 requested a review from a team as a code owner August 12, 2026 15:17
@pskiran1

Copy link
Copy Markdown
Contributor Author

/ok to test 8b3dbaf

@devin-ai-integration devin-ai-integration Bot 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.

Devin Review found 2 potential issues.

Open in Devin Review

Comment thread lib/llm/src/http/service/service_v2.rs Outdated
Comment thread lib/llm/src/http/service/service_v2.rs Outdated
@coderabbitai

coderabbitai Bot commented Aug 12, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

The HTTP service now parses response request bodies explicitly, validates JSON-compatible content types, and uses tolerant JSON parsing. Unmatched routes return OpenAI-compatible JSON 404 responses. Integration tests cover request and routing errors.

Changes

OpenAI-compatible HTTP error handling

Layer / File(s) Summary
Explicit response request parsing
lib/llm/src/http/service/openai.rs
handler_responses accepts raw body bytes, validates the content type, and uses parse_json_request for tolerant parsing.
Fallback routing and validation
lib/llm/src/http/service/openai.rs, lib/llm/src/http/service/service_v2.rs
The merged router uses unmatched_route_fallback for standardized 404 JSON errors. Integration tests cover unsupported content types, malformed bodies, unknown response IDs, and unknown paths.

Estimated code review effort: 3 (Moderate) | ~20 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description covers the changes, validation, and related issue, but it omits the required reviewer-start section and leaves both issue paths selected. Add the required "Where should the reviewer start?" section and select only the applicable Related Issues path with a valid issue reference.
✅ Passed checks (4 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly summarizes the main change: JSON errors for invalid content types and unknown routes.

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@lib/llm/src/http/service/openai.rs`:
- Around line 2953-2956: Move the JSON Content-Type validation out of
handler_responses and into route middleware or a custom extractor that examines
request parts before Axum extracts body: Bytes. Ensure invalid media types
receive an immediate 415 response, while handler_responses continues to call
parse_json_request only after validation succeeds.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: c950200f-5e3d-40f3-b90a-63087365bdda

📥 Commits

Reviewing files that changed from the base of the PR and between f4625cd and 8b3dbaf.

📒 Files selected for processing (2)
  • lib/llm/src/http/service/openai.rs
  • lib/llm/src/http/service/service_v2.rs

Comment thread lib/llm/src/http/service/openai.rs Outdated
@datadog-official

This comment has been minimized.

@pskiran1
pskiran1 marked this pull request as draft August 12, 2026 16:00
Signed-off-by: Sai Kiran Polisetty <spolisetty@nvidia.com>
@pskiran1
pskiran1 marked this pull request as ready for review August 12, 2026 16:49
@pskiran1

pskiran1 commented Aug 12, 2026 •

Copy link
Copy Markdown
Contributor Author

/ok to test 8f65456

Comment thread lib/llm/src/http/service/openai.rs Outdated
Comment thread lib/llm/src/http/service/openai.rs Outdated
Comment thread lib/llm/src/http/service/service_v2.rs Outdated
Comment thread lib/llm/src/http/service/service_v2.rs Outdated
Signed-off-by: Sai Kiran Polisetty <spolisetty@nvidia.com>
@pskiran1
pskiran1 requested a review from a team as a code owner August 18, 2026 14:46
@pskiran1
pskiran1 requested a review from a team as a code owner August 18, 2026 14:46
@pskiran1
pskiran1 requested a review from rmccorm4 August 18, 2026 14:59
@pskiran1

pskiran1 commented Aug 18, 2026 •

Copy link
Copy Markdown
Contributor Author

/ok to test 8f65456

Signed-off-by: Sai Kiran Polisetty <spolisetty@nvidia.com>
@pskiran1
pskiran1 requested a review from a team as a code owner August 18, 2026 15:47
@rmccorm4
rmccorm4 enabled auto-merge (squash) August 18, 2026 15:53
@pskiran1

Copy link
Copy Markdown
Contributor Author

/ok to test 8f65456

@rmccorm4
rmccorm4 merged commit f5802d3 into main Aug 18, 2026
119 checks passed
@rmccorm4
rmccorm4 deleted the spolisetty/dis-2541-a4-malformed-non-json-http-response-body branch August 18, 2026 16:58
ayaangazali added a commit to ayaangazali/dynamo that referenced this pull request Aug 27, 2026
error envelope for a bad `Content-Type`, an oversized body and malformed JSON,
by reading the body through `read_json_request_body` and `parse_json_request`.

Eight handlers were left on the plain `Json<T>` extractor and still return
Axum's `text/plain` rejection, so the envelope depends on which endpoint the
client happened to call:

    POST /v1/responses  + Content-Type: text/plain
      415  application/json  {"message":"Expected request with Content-Type application/json",...}

    POST /v1/embeddings + Content-Type: text/plain
      415  text/plain        Expected request with `Content-Type: application/json`

A client that parses the error body works against one endpoint and fails
against the other, for the same mistake and the same status code.

Route the remaining handlers through the same two helpers: embeddings,
classify, pooling, images, image edits, videos, video stream and audio speech.
They already took `HeaderMap` and already returned
`Result<Response, ErrorResponse>`, so each is a signature swap plus the two
lines ai-dynamo#13102 established.

`images_edits` validates `input_reference` and then delegates to `images`,
which now consumes a `Body` it has already read. The part of `images` after
parsing moves into `images_with_request`, called by both.

No change to any success path, and no change to the error text; only the
envelope and content type on the eight endpoints that were inconsistent.

Signed-off-by: ayaangazali <ayaangazali.work@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

fix frontend `python -m dynamo.frontend` and `dynamo-run in=http|text|grpc` size/L

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants