XINCGer/Unity3DTraining · error · InvalidOperationException

Stream.Read returned a negative count

Error message

Stream.Read returned a negative count

What it means

When refilling its internal buffer, CodedInputStream calls input.Read(...) and requires a non-negative count, as the Stream contract mandates. A negative return means the underlying Stream implementation is buggy or misbehaving, so InvalidOperationException is thrown. This surfaces a problem in the custom stream, not in the protobuf data itself.

Solutions

  1. Fix the custom Stream.Read implementation to return 0 at end of stream and to throw exceptions on errors instead of returning negative values.
  2. Map native error codes to exceptions (throw IOException) rather than returning them from Read.
  3. If a third-party stream is at fault, wrap it in an adapter Stream that sanitizes negative returns.
  4. Test the stream with a contract check: Read must return 0..buffer.Length and only 0 at EOF.

Example fix

// before
public override int Read(byte[] buffer, int offset, int count)
{
    int n = NativeRecv(...);
    return n; // may be -1 on error
}
// after
public override int Read(byte[] buffer, int offset, int count)
{
    int n = NativeRecv(...);
    if (n < 0) throw new IOException("recv failed: " + n);
    return n;
}
Defensive patterns

Strategy: type-guard

Validate before calling

// contract check for custom streams before use
var tmp = new byte[1];
int probe = stream.Read(tmp, 0, 1);
if (probe < 0) throw new IOException("Stream.Read violates contract (negative return)");

Type guard

bool ConformsToStreamContract(Stream s) { try { var b = new byte[1]; return s.Read(b, 0, 1) >= 0; } catch { return false; } }

Try / catch

try { message.MergeFrom(codedInput); } catch (InvalidOperationException ex) when (ex.Message.Contains("negative count")) { logger.LogError(ex, "Wrapped Stream returned negative from Read — fix the stream implementation"); }

Prevention

When it happens

Trigger: Wrapping CodedInputStream around a custom Stream subclass whose Read override returns -1 (common mistake: returning -1 instead of 0 at end of stream) or a negative value from an unchecked native call.

Common situations: Network stream wrappers where recv() error codes (-1) are propagated as the Read result; Unity/games with hand-written socket streams; wrappers around unmanaged decoders returning error codes from Read.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of XINCGer/Unity3DTraining@016f98412e (2026-09-12). Data as JSON: /api/errors/69fc9bb345cc9b4e. Report an issue: GitHub.

Appendix: source

Thrown at NetWorkAndResources/Socket_Protobuff/Assets/Plugins/Google.Protobuf/CodedInputStream.cs:1032

            {
                // Oops, we hit a limit.
                if (mustSucceed)
                {
                    throw InvalidProtocolBufferException.TruncatedMessage();
                }
                else
                {
                    return false;
                }
            }

            totalBytesRetired += bufferSize;

            bufferPos = 0;
            bufferSize = (input == null) ? 0 : input.Read(buffer, 0, buffer.Length);
            if (bufferSize < 0)
            {
                throw new InvalidOperationException("Stream.Read returned a negative count");
            }
            if (bufferSize == 0)
            {
                if (mustSucceed)
                {
                    throw InvalidProtocolBufferException.TruncatedMessage();
                }
                else
                {
                    return false;
                }
            }
            else
            {
                RecomputeBufferSizeAfterLimit();
                int totalBytesRead =
                    totalBytesRetired + bufferSize + bufferSizeAfterLimit;
                if (totalBytesRead > sizeLimit || totalBytesRead < 0)

View on GitHub (pinned to 016f98412e)