XINCGer/Unity3DTraining · error · ArgumentOutOfRangeException
Offset must be within the buffer
Error message
Offset must be within the buffer
What it means
CodedInputStream's byte[]/offset/length constructor validates that the offset lies within the supplied buffer. If offset is negative or greater than buffer.Length, ArgumentOutOfRangeException('Offset must be within the buffer') is thrown before any parsing happens. This is defensive argument validation in Google.Protobuf; the stream is never created.
Solutions
- Clamp/validate the offset before constructing: ensure 0 <= offset <= buffer.Length.
- Verify the offset computation (e.g. bytes consumed so far) against the actual buffer length actually received.
- If the offset can legitimately be at/after the end, guard with 'if (offset >= buffer.Length) skip/return' instead of constructing a reader.
- Use a checked bounds helper so offsets are always derived from buffer.Length rather than hard-coded assumptions.
Example fix
// before
var stream = new CodedInputStream(payload, offset, payload.Length - offset);
// after
if (offset < 0 || offset > payload.Length)
throw new ArgumentException($"Bad offset {offset} for buffer of {payload.Length} bytes");
var stream = new CodedInputStream(payload, offset, payload.Length - offset); Defensive patterns
Strategy: validation
Validate before calling
if (offset < 0 || offset > buffer.Length) throw new ArgumentException($"offset {offset} out of bounds for buffer length {buffer.Length}", nameof(offset)); Type guard
bool IsValidOffset(byte[] buffer, int offset) => buffer != null && offset >= 0 && offset <= buffer.Length;
Try / catch
try { var s = new CodedInputStream(buffer, offset, length); ... } catch (ArgumentOutOfRangeException ex) { logger.LogError(ex, "Invalid buffer window offset={Offset} len={Length}", offset, length); return null; } Prevention
- Always derive offset from bytes-consumed counters scoped to the current buffer object.
- Null-check and length-check buffers received from the network before framing.
- Write a unit test for the framing function covering empty buffers and offset == buffer.Length.
When it happens
Trigger: new CodedInputStream(buffer, offset, length) where offset < 0 or offset > buffer.Length. E.g. passing an offset captured from a previous read past the buffer end, or -1 from a failed lookup used directly as the offset.
Common situations: Fragmenting a received socket payload into messages and computing the next message offset incorrectly; reusing a stale offset after the buffer was replaced with a shorter array; passing byte[] objects received from unmanaged/interop code with mismatched lengths.
Related errors
- Length must be non-negative and 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/711b93927ed9a150.
Report an issue: GitHub.
Appendix: source
Thrown at NetWorkAndResources/Socket_Protobuff/Assets/Plugins/Google.Protobuf/CodedInputStream.cs:136
// Note that the checks are performed such that we don't end up checking obviously-valid things
// like non-null references for arrays we've just created.
/// <summary>
/// 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.View on GitHub (pinned to 016f98412e)