XINCGer/Unity3DTraining · error · ArgumentOutOfRangeException
Length must be non-negative and within the buffer
Error message
Length must be non-negative and within the buffer
What it means
The same constructor validates that the requested length is non-negative and that offset+length does not run past the end of the buffer. If length < 0 or offset + length > buffer.Length, ArgumentOutOfRangeException('Length must be non-negative and within the buffer') is thrown. This prevents the parser from ever reading beyond the supplied data.
Solutions
- Compute length as buffer.Length - offset and validate it is >= 0 before constructing the reader.
- Validate any length-prefix from the wire against the actual bytes available before honoring it.
- Log the buffer length, offset, and computed length at the failure site to find the bad arithmetic.
- If truncation is expected, handle it at the framing layer (buffer more data) instead of passing an over-large length.
Example fix
// before
var stream = new CodedInputStream(buf, pos, declaredLen);
// after
int available = buf.Length - pos;
int len = Math.Min(declaredLen, available);
if (len < 0) throw new InvalidDataException("Truncated message");
var stream = new CodedInputStream(buf, pos, len); Defensive patterns
Strategy: validation
Validate before calling
int avail = buffer.Length - offset;
if (length < 0 || length > avail) throw new ArgumentException($"length {length} invalid; only {avail} bytes available at offset {offset}"); Type guard
bool IsValidWindow(byte[] buffer, int offset, int length) => offset >= 0 && length >= 0 && offset + length <= buffer.Length;
Try / catch
try { var s = new CodedInputStream(buffer, offset, length); ... } catch (ArgumentOutOfRangeException ex) { logger.LogError(ex, "Bad buffer window"); bufferMoreDataFromSocket(); } Prevention
- Never trust wire-declared length prefixes; clamp to bytes actually received.
- Compute lengths as end - start only after asserting end >= start.
- Keep message framing in one helper so length arithmetic is tested once.
When it happens
Trigger: new CodedInputStream(buffer, offset, length) with a negative length (e.g. computing length = end - start where end < start), or length so large that offset + length exceeds buffer.Length (e.g. assuming a length prefix that exceeds the actual payload).
Common situations: Framing messages from a stream where the declared message length is trusted but the packet was truncated; off-by-one in start/end index arithmetic; reading a length header in the wrong endianness producing a huge length.
Related errors
- Offset must be within the buffer
- Size limit must be positive
- Recursion limit must be positive
- Stream.Read returned a negative count
- SpaceLeft can only be called on CodedOutputStreams that are…
AI-assisted analysis of XINCGer/Unity3DTraining@016f98412e (2026-09-12).
Data as JSON: /api/errors/a6cd234e185df493.
Report an issue: GitHub.
Appendix: source
Thrown at NetWorkAndResources/Socket_Protobuff/Assets/Plugins/Google.Protobuf/CodedInputStream.cs:140
/// Creates a new CodedInputStream reading data from the given byte array.
/// </summary>
public CodedInputStream(byte[] buffer) : this(null, ProtoPreconditions.CheckNotNull(buffer, "buffer"), 0, buffer.Length)
{
}
/// <summary>
/// Creates a new <see cref="CodedInputStream"/> that reads from the given byte array slice.
/// </summary>
public CodedInputStream(byte[] buffer, int offset, int length)
: this(null, ProtoPreconditions.CheckNotNull(buffer, "buffer"), offset, offset + length)
{
if (offset < 0 || offset > buffer.Length)
{
throw new ArgumentOutOfRangeException("offset", "Offset must be within the buffer");
}
if (length < 0 || offset + length > buffer.Length)
{
throw new ArgumentOutOfRangeException("length", "Length must be non-negative and within the buffer");
}
}
/// <summary>
/// Creates a new <see cref="CodedInputStream"/> reading data from the given stream, which will be disposed
/// when the returned object is disposed.
/// </summary>
/// <param name="input">The stream to read from.</param>
public CodedInputStream(Stream input) : this(input, false)
{
}
/// <summary>
/// Creates a new <see cref="CodedInputStream"/> reading data from the given stream.
/// </summary>
/// <param name="input">The stream to read from.</param>
/// <param name="leaveOpen"><c>true</c> to leave <paramref name="input"/> open when the returned
/// <c cref="CodedInputStream"/> is disposed; <c>false</c> to dispose of the given stream when theView on GitHub (pinned to 016f98412e)