dotnet/yarp · error · Exception

Read {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.

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)

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.