canopy-network/canopy · error

field value exceeds buffer bounds

Error message

field value exceeds buffer bounds

What it means

After reading the length prefix of a matching BytesType field, GetRawProtoField checks that offset+valueLen stays within the buffer. If the declared length runs past the end of the bytes, the payload is truncated or corrupt, so extraction stops rather than reading out of bounds.

Source

Thrown at lib/codec/codec.go:88

		fieldNum, wireType, tagLen := protowire.ConsumeTag(protoBytes[offset:])
		if tagLen < 0 {
			return nil, fmt.Errorf("invalid tag at offset %d", offset)
		}
		offset += tagLen
		// check if this is the field we're looking for
		if int(fieldNum) == fieldNumber {
			// for length-delimited fields (like messages), we need to read the length
			if wireType == protowire.BytesType {
				// read the length of the field value
				valueLen, lenBytes := protowire.ConsumeVarint(protoBytes[offset:])
				if lenBytes < 0 {
					return nil, fmt.Errorf("invalid length at offset %d", offset)
				}
				// calculate the new offset
				offset += lenBytes
				// extract the field value bytes
				if offset+int(valueLen) > len(protoBytes) {
					return nil, fmt.Errorf("field value exceeds buffer bounds")
				}
				// make buffer to return
				fieldBytes := make([]byte, valueLen)
				// copy into the buffer
				copy(fieldBytes, protoBytes[offset:offset+int(valueLen)])
				// return the value
				return fieldBytes, nil
			} else {
				// for other wire types, consume the value directly
				valueLen := protowire.ConsumeFieldValue(fieldNum, wireType, protoBytes[offset:])
				if valueLen < 0 {
					return nil, fmt.Errorf("invalid field value at offset %d", offset)
				}
				if offset+valueLen > len(protoBytes) {
					return nil, fmt.Errorf("field value exceeds buffer bounds")
				}
				fieldBytes := make([]byte, valueLen)
				copy(fieldBytes, protoBytes[offset:offset+valueLen])

View on GitHub (pinned to ee8197d91d)

Solutions

  1. Confirm the buffer is the complete, unmodified output of proto.Marshal for the message.
  2. Run proto.Unmarshal on the full buffer as a validity gate before raw field extraction.
  3. If the bytes are composed from multiple sources, ensure field boundaries are not being cut.

Example fix

// before
raw, _ := codec.GetRawProtoField(partialBlob, 2)
// after
var m mypb.Event
if err := proto.Unmarshal(fullBlob, &m); err != nil { return err }
raw, err := codec.GetRawProtoField(fullBlob, 2)
Defensive patterns

Strategy: validation

Validate before calling

var probe pb.Event
if err := proto.Unmarshal(data, &probe); err != nil {
    return fmt.Errorf("buffer failed proto validation: %w", err)
}

Try / catch

raw, err := codec.GetRawProtoField(data, fieldNum)
if err != nil && strings.Contains(err.Error(), "exceeds buffer bounds") {
    return fmt.Errorf("truncated field payload: %w", err)
}

Prevention

When it happens

Trigger: GetRawProtoField on a buffer where the target field's varint length claims more bytes than actually remain — truncated or mutated wire data.

Common situations: Storage/network truncation; manually edited proto bytes; mixing bytes from two different messages; a length varint misread because the buffer was sliced mid-field.

Understand the failure class

Background: "cannot parse invalid wire-format data", "cannot unmarshal", "failed unmarshalling": protobuf unmarshal errors explained — this error's family across 10 libraries.

Related errors


AI-assisted analysis of canopy-network/canopy@ee8197d91d (2026-09-06). Data as JSON: /api/errors/a146d389fcd3cb4e. Report an issue: GitHub.