Skip to content

fix(aspnetcore): return 400 InvalidParams for invalid initialize params instead of 500 - #1884

Closed
Digvijay wants to merge 1 commit into
modelcontextprotocol:mainfrom
Digvijay:fix/788-initialize-invalid-params-status
Closed

Digvijay wants to merge 1 commit into
modelcontextprotocol:mainfrom
Digvijay:fix/788-initialize-invalid-params-status

Conversation

@Digvijay

Copy link
Copy Markdown

Summary

An initialize request with a structurally valid JSON-RPC envelope but invalid params (for example a missing required clientInfo.version) returned an opaque 500 Internal Server Error instead of a client-facing error. This made it very hard for callers to tell that the problem was in their request body.

Root cause

For legacy protocol revisions, StreamableHttpPostTransport.HandlePostAsync eagerly deserializes the initialize params before the message reaches the session's JSON-RPC error handling loop. When the params are invalid, JsonSerializer.Deserialize throws a JsonException that propagates unhandled through HandlePostRequestAsync up to the ASP.NET Core pipeline, producing a raw 500.

(Malformed JSON envelopes were already handled at the boundary and returned 400; only the eager initialize params path was missing.)

Fix

Catch the JsonException at the HTTP boundary in StreamableHttpHandler.HandlePostRequestAsync while the response has not started, and emit a conformant JSON-RPC error — 400 Bad Request with InvalidParams (-32602) — echoing the request id, mirroring the existing malformed-JSON handling. The Core transport stays HTTP-agnostic (no status-code knowledge leaks into it).

Tests

Added PostInitializeWithMissingRequiredParam_Returns400_InvalidParams_EchoesRequestId to StreamableHttpServerConformanceTests, which posts an initialize request whose clientInfo omits the required version. It is red before the fix (500) and green after (400 + InvalidParams, id echoed).

Validated the full ModelContextProtocol.AspNetCore.Tests suite locally on net8.0, net9.0, and net10.0 (Docker tests included) — all green.

Fixes #788

Note

I used an AI assistant (GitHub Copilot) to help investigate the issue, implement the fix, and write the test. I ran the tests myself and verified the results.

…ms instead of 500

The legacy initialize handshake eagerly deserializes its params inside StreamableHttpPostTransport before the message reaches the session's JSON-RPC error handling. A structurally valid JSON-RPC envelope whose initialize params were invalid (e.g. a missing required clientInfo.version) threw a JsonException that bubbled up as an opaque 500 Internal Server Error.

Catch that JsonException at the HTTP boundary while the response has not started and emit a conformant JSON-RPC error (400 InvalidParams, -32602) that echoes the request id, mirroring the existing malformed-JSON handling. The Core transport stays HTTP-agnostic.

Fixes modelcontextprotocol#788
@Digvijay

Copy link
Copy Markdown
Author

Closing as a duplicate. I missed that #1709 already addresses #788 with the same approach (validate initialize params at the HTTP boundary, return 400 with JSON-RPC InvalidParams echoing the request id, plus a missing clientInfo.version test) — and it's already APPROVED, mergeable, and green. Apologies for the noise; deferring to #1709. Thanks @lntutor / @PranavSenthilnathan.

@Digvijay Digvijay closed this Sep 18, 2026
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.

Passing a malformed body throws a 500 error instead of 400. Very hard to figure out what is incorrect in the request being issued by the caller

1 participant