canopy-network/canopy · error
invalid tag at offset %d
Error message
invalid tag at offset %d
What it means
GetRawProtoField manually walks protobuf wire format. At each offset it decodes a field tag with protowire.ConsumeTag; a negative tag length means the bytes at that offset are not a valid varint tag — the buffer is corrupt, truncated, or not protobuf wire data at all.
Source
Thrown at lib/codec/codec.go:72
// ToAny() packs a protobuf message to a generic any
func (p *Protobuf) ToAny(message proto.Message) (*anypb.Any, error) {
return anypb.New(message)
}
// FromAny() converts a proto any to the protobuf message
func (p *Protobuf) FromAny(any *anypb.Any) (proto.Message, error) {
return anypb.UnmarshalNew(any, proto.UnmarshalOptions{})
}
// GetRawProtoField extracts the raw bytes for field number from a proto message
func GetRawProtoField(protoBytes []byte, fieldNumber int) ([]byte, error) {
var offset int
// parse the proto bytes to find a field
for offset < len(protoBytes) {
// decode the field tag (field number + wire type)
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 returnView on GitHub (pinned to ee8197d91d)
Solutions
- Verify the bytes come from proto.Marshal (or codec.Marshal) of the expected message — log/inspect the first few bytes.
- If the data may be JSON or another format, branch on format before calling GetRawProtoField and decode accordingly.
- Round-trip sanity check: proto.Unmarshal(bytes, &msg{}) should succeed before doing raw wire scanning.
Example fix
// before
raw, _ := codec.GetRawProtoField(jsonBytes, 1)
// after
protoBytes, err := codec.Protobuf{}.Marshal(msg)
if err != nil { return err }
raw, err := codec.GetRawProtoField(protoBytes, 1) Defensive patterns
Strategy: type-guard
Validate before calling
if len(data) == 0 {
return fmt.Errorf("empty proto bytes")
}
var probe pb.Event
if err := proto.Unmarshal(data, &probe); err != nil {
return fmt.Errorf("not valid protobuf wire data: %w", err)
} Type guard
func isProtoWireData(data []byte) bool {
var m ptypes.DynamicAny
return proto.Unmarshal(data, &m.Message) == nil || protobufUnmarshalOK(data)
} Try / catch
raw, err := codec.GetRawProtoField(data, fieldNum)
if err != nil && strings.Contains(err.Error(), "invalid tag") {
return fmt.Errorf("corrupt or non-proto payload: %w", err)
} Prevention
- Only feed GetRawProtoField bytes produced by proto.Marshal.
- Tag stored blobs with a format marker so JSON/proto are never confused.
- Round-trip test (Marshal then GetRawProtoField) in unit tests.
When it happens
Trigger: Calling GetRawProtoField (directly or via entryKeyOrZero / BytesToBlockHash) with bytes that are not valid proto wire format, or a truncated slice where the loop lands mid-tag.
Common situations: Passing JSON, hex/base64-decoded-but-wrong data, or a doubly/mis-encoded payload instead of proto.Marshal output; slicing the proto bytes at the wrong offset before calling; corrupted storage reads.
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
- invalid field value at offset %d
- invalid length at offset %d
- field value exceeds buffer bounds
- ErrFieldNotFound
- unsupported wire type %d
AI-assisted analysis of canopy-network/canopy@ee8197d91d (2026-09-06).
Data as JSON: /api/errors/1dfbab09f97a65ee.
Report an issue: GitHub.