You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
RawHttpConformanceTests.July2026Post_MissingRequiredCapability_Returns400 intermittently receives HTTP 200 instead of HTTP 400.
The server correctly produces a MissingRequiredClientCapabilityException and sends the corresponding JSON-RPC error. However, the HTTP status can already be committed as 200 before that error reaches the response callback.
The timer starts after the request is queued for dispatch. If dispatch and handler execution exceed that window, DeferredHeaderFlushAsync invokes the response-starting callback with null and flushes the default HTTP 200 headers.
When the MissingRequiredClientCapability JSON-RPC error arrives later, _httpResponseStarted is already true, so the callback cannot update the HTTP status to 400. The JSON-RPC error is therefore returned over an already-committed HTTP 200 response.
This makes the conformance test dependent on scheduling and machine load rather than solely on server behavior.
Description
RawHttpConformanceTests.July2026Post_MissingRequiredCapability_Returns400intermittently receives HTTP 200 instead of HTTP 400.The server correctly produces a
MissingRequiredClientCapabilityExceptionand sends the corresponding JSON-RPC error. However, the HTTP status can already be committed as 200 before that error reaches the response callback.Evidence
The failure occurred in:
BadRequestOKThe test log shows:
requires_samplingthrewMissingRequiredClientCapabilityException.--blame-crashonly attached its standard collector.The same test previously failed with the same 200-versus-400 result on an earlier workflow attempt and then passed when rerun:
The failure has occurred under different configurations and target frameworks, while the other frameworks in the same jobs passed.
Root cause
StreamableHttpPostTransportdefers committing response headers for a fixed 250 ms window:The timer starts after the request is queued for dispatch. If dispatch and handler execution exceed that window,
DeferredHeaderFlushAsyncinvokes the response-starting callback withnulland flushes the default HTTP 200 headers.When the
MissingRequiredClientCapabilityJSON-RPC error arrives later,_httpResponseStartedis already true, so the callback cannot update the HTTP status to 400. The JSON-RPC error is therefore returned over an already-committed HTTP 200 response.This makes the conformance test dependent on scheduling and machine load rather than solely on server behavior.
Note
This issue was drafted with GitHub Copilot.