{"record":{"id":"69fc9bb345cc9b4e","repo":"XINCGer/Unity3DTraining","slug":"stream-read-returned-a-negative-count","errorCode":null,"errorMessage":"Stream.Read returned a negative count","messagePattern":"Stream\\.Read returned a negative count","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"NetWorkAndResources/Socket_Protobuff/Assets/Plugins/Google.Protobuf/CodedInputStream.cs","lineNumber":1032,"sourceCode":"            {\n                // Oops, we hit a limit.\n                if (mustSucceed)\n                {\n                    throw InvalidProtocolBufferException.TruncatedMessage();\n                }\n                else\n                {\n                    return false;\n                }\n            }\n\n            totalBytesRetired += bufferSize;\n\n            bufferPos = 0;\n            bufferSize = (input == null) ? 0 : input.Read(buffer, 0, buffer.Length);\n            if (bufferSize < 0)\n            {\n                throw new InvalidOperationException(\"Stream.Read returned a negative count\");\n            }\n            if (bufferSize == 0)\n            {\n                if (mustSucceed)\n                {\n                    throw InvalidProtocolBufferException.TruncatedMessage();\n                }\n                else\n                {\n                    return false;\n                }\n            }\n            else\n            {\n                RecomputeBufferSizeAfterLimit();\n                int totalBytesRead =\n                    totalBytesRetired + bufferSize + bufferSizeAfterLimit;\n                if (totalBytesRead > sizeLimit || totalBytesRead < 0)","sourceCodeStart":1014,"sourceCodeEnd":1050,"githubUrl":"https://github.com/XINCGer/Unity3DTraining/blob/016f98412ea5e11756b286736f479b66ab6216d5/NetWorkAndResources/Socket_Protobuff/Assets/Plugins/Google.Protobuf/CodedInputStream.cs#L1014-L1050","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Fix the custom Stream.Read implementation to return 0 at end of stream and to throw exceptions on errors instead of returning negative values.","Map native error codes to exceptions (throw IOException) rather than returning them from Read.","If a third-party stream is at fault, wrap it in an adapter Stream that sanitizes negative returns.","Test the stream with a contract check: Read must return 0..buffer.Length and only 0 at EOF."],"exampleFix":"// before\npublic override int Read(byte[] buffer, int offset, int count)\n{\n    int n = NativeRecv(...);\n    return n; // may be -1 on error\n}\n// after\npublic override int Read(byte[] buffer, int offset, int count)\n{\n    int n = NativeRecv(...);\n    if (n < 0) throw new IOException(\"recv failed: \" + n);\n    return n;\n}","handlingStrategy":"type-guard","validationCode":"// contract check for custom streams before use\nvar tmp = new byte[1];\nint probe = stream.Read(tmp, 0, 1);\nif (probe < 0) throw new IOException(\"Stream.Read violates contract (negative return)\");","typeGuard":"bool ConformsToStreamContract(Stream s) { try { var b = new byte[1]; return s.Read(b, 0, 1) >= 0; } catch { return false; } }","tryCatchPattern":"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\"); }","preventionTips":["Custom Stream.Read must return 0 at EOF and throw IOException on errors, never a negative number.","Unit-test custom streams against the Stream contract before wiring them into parsers.","Wrap unmanaged/native reads in an adapter that converts error codes to exceptions."],"tags":["protobuf","stream","csharp"],"backgroundTag":"internal-invariant-violation","analyzedSha":"016f98412ea5e11756b286736f479b66ab6216d5","analyzedAt":"2026-09-12T01:08:58.711Z","contentChangedAt":"2026-09-12T01:08:58.711Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}