dotnet/yarp · error · Exception

Read bytes, expected 0 after sending Goodbye.

Error message

Read {read} bytes, expected 0 after sending Goodbye.

What it means

Asserted at the end of RawUpgradeScenario's echo loop. After writing byte value 255 (the agreed 'Goodbye' marker), the scenario expects the server to close/stop echoing, so ReadAsync should report 0 bytes read. A non-zero read means the server kept echoing or did not recognize the goodbye, so an Exception is thrown with the actual byte count.

Solutions

  1. Use the matching test backend that stops echoing after byte 255 and returns 0.
  2. Confirm the full 256-byte exchange completed before this point (errors 94/95 would fire first if echo was broken).
  3. Check the connection was not reset midway, which can surface as unexpected reads.
Defensive patterns

Strategy: try-catch

Try / catch

try { await RawUpgradeScenario.RunAsync(client, args, cancellation); }
catch (Exception ex) when (ex.Message.Contains("expected 0 after sending Goodbye")) {
    Console.Error.WriteLine("Backend did not stop echoing after Goodbye; use the matching echo test server.");
    return 1;
}

Prevention

When it happens

Trigger: Running RawUpgradeScenario against a raw-upgrade endpoint that does not stop echoing after receiving byte 255, or where the stream semantics differ (e.g. it echoes the final byte too).

Common situations: Backend echo implementation that mirrors every byte including the goodbye; partial network read; the upgraded stream being half-closed differently than the scenario assumes.

Related errors


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

Appendix: source

Thrown at testassets/TestClient/Scenarios/RawUpgradeScenario.cs:52

        if (response.StatusCode != HttpStatusCode.SwitchingProtocols)
        {
            throw new InvalidOperationException("Expected status 101 Switching Protocols!");
        }

        var rawStream = await response.Content.ReadAsStreamAsync(cancellation);
        Console.WriteLine("Acquired upgraded stream. Testing bidirectional echo...");
        stopwatch.Restart();
        var buffer = new byte[1];
        for (var i = 0; i <= 255; i++)
        {
            buffer[0] = (byte)i;
            await rawStream.WriteAsync(buffer, cancellation);
            var read = await rawStream.ReadAsync(buffer, cancellation);
            if (i == 255)
            {
                if (read != 0)
                {
                    throw new Exception($"Read {read} bytes, expected 0 after sending Goodbye.");
                }

                Console.WriteLine();
            }
            else
            {
                if (read != 1)
                {
                    throw new Exception($"Read {read} bytes, expected 1.");
                }

                if (buffer[0] != i)
                {
                    throw new Exception($"Received {buffer[0]}, expected {i}.");
                }

                Console.Write(".");
            }

View on GitHub (pinned to bd11867bee)