dotnet/yarp · error · InvalidOperationException

Expected status 409 Conflict!

Error message

Expected status 409 Conflict!

What it means

Asserted by the Http2PostExpectContinueScenario in the SampleClient. It POSTs a 10 MB body over HTTP/2 with Expect: 100-continue to the /api/skipbody endpoint and asserts the server responds 409 Conflict (the test endpoint signals it skipped the body). An InvalidOperationException is thrown when the status is anything other than Conflict, indicating the upgrade/continue handshake or the test endpoint did not behave as expected.

Source

Thrown at testassets/TestClient/Scenarios/Http2PostExpectContinueScenario.cs:44

            AutomaticDecompression = DecompressionMethods.None,
            UseCookies = false,
            UseProxy = false,
        })
        using (var client = new HttpMessageInvoker(handler))
        {
            var targetUri = new Uri(new Uri(args.Target, UriKind.Absolute), "api/skipbody");
            var stopwatch = Stopwatch.StartNew();
            var request = new HttpRequestMessage(HttpMethod.Post, targetUri);
            request.Version = new Version(2, 0);
            request.Headers.ExpectContinue = true;
            request.Content = new StringContent(new string('a', 1024 * 1024 * 10));
            Console.WriteLine($"Calling {targetUri} with HTTP/2");

            var response = await client.SendAsync(request, cancellation);
            Console.WriteLine($"Received response: {(int)response.StatusCode} in {stopwatch.ElapsedMilliseconds} ms");
            if (response.StatusCode != HttpStatusCode.Conflict)
            {
                throw new InvalidOperationException($"Expected status 409 Conflict!");
            }
        }
    }
}

View on GitHub (pinned to bd11867bee)

Solutions

  1. Run the scenario against the matching test server (the ReverseProxy.Code/Telemetry/test assets that implement /api/skipbody returning 409).
  2. Confirm the target supports HTTP/2 (TLS with ALPN h2, or HTTP/2 cleartext where configured).
  3. Verify --target points to the proxy/frontend address the scenario expects, not a plain backend.
  4. Check the printed received status code for a hint (e.g. 404 means the endpoint is missing).
Defensive patterns

Strategy: try-catch

Validate before calling

// Before running, verify the endpoint contract.
using var probe = new HttpClient();
var r = await probe.GetAsync(new Uri(args.Target, "api/skipbody"));
if (r.StatusCode != HttpStatusCode.Conflict)
    Console.Error.WriteLine($"Warning: /api/skipbody returned {r.StatusCode}, scenario will fail.");

Try / catch

try { await Http2PostExpectContinueScenario.RunAsync(client, args, cancellation); }
catch (InvalidOperationException ex) when (ex.Message.Contains("409 Conflict")) {
    Console.Error.WriteLine("Target did not return 409 from /api/skipbody; wrong --target or HTTP/2 unavailable.");
    return 1;
}

Prevention

When it happens

Trigger: Running SampleClient --scenario Http2PostExpectContinueScenario against a target whose /api/skipbody does not return 409, or where HTTP/2 is unavailable so the request behaves differently.

Common situations: Pointing --target at a server that does not implement the skipbody test endpoint; HTTP/2 not negotiated (TLS/ALPN missing); an intermediary that strips Expect; the proxy not forwarding the large body correctly.

Related errors


AI-assisted analysis of dotnet/yarp@bd11867bee (2026-08-13). Data as JSON: /api/errors/0cfe84f4cb92bec9. Report an issue: GitHub.