{"record":{"id":"19f9e28449566093","repo":"canopy-network/canopy","slug":"errfieldnotfound","errorCode":"ErrFieldNotFound","errorMessage":"%w: %d","messagePattern":"%w: %d","errorType":"validation","errorClass":"ErrFieldNotFound","httpStatus":null,"severity":"warning","filePath":"lib/codec/codec.go","lineNumber":118,"sourceCode":"\t\t\t\t\treturn nil, fmt.Errorf(\"invalid field value at offset %d\", offset)\n\t\t\t\t}\n\t\t\t\tif offset+valueLen > len(protoBytes) {\n\t\t\t\t\treturn nil, fmt.Errorf(\"field value exceeds buffer bounds\")\n\t\t\t\t}\n\t\t\t\tfieldBytes := make([]byte, valueLen)\n\t\t\t\tcopy(fieldBytes, protoBytes[offset:offset+valueLen])\n\t\t\t\treturn fieldBytes, nil\n\t\t\t}\n\t\t} else {\n\t\t\t// skip this field\n\t\t\tskipLen := protowire.ConsumeFieldValue(fieldNum, wireType, protoBytes[offset:])\n\t\t\tif skipLen < 0 {\n\t\t\t\treturn nil, fmt.Errorf(\"invalid field value at offset %d\", offset)\n\t\t\t}\n\t\t\toffset += skipLen\n\t\t}\n\t}\n\treturn nil, fmt.Errorf(\"%w: %d\", ErrFieldNotFound, fieldNumber)\n}\n\n// NullifyProtoField removes a field from protobytes without unmarshalling\nfunc NullifyProtoField(protoBytes []byte, fieldNumber int) ([]byte, error) {\n\tvar offset int\n\t// create a buffer to store the result\n\tresult := make([]byte, 0, len(protoBytes))\n\t// iterate through the bytes\n\tfor offset < len(protoBytes) {\n\t\t// remember the start position of this field\n\t\tfieldStart := offset\n\t\t// decode the field tag\n\t\tfieldNum, wireType, tagLen := protowire.ConsumeTag(protoBytes[offset:])\n\t\tif tagLen < 0 {\n\t\t\treturn nil, fmt.Errorf(\"invalid tag at offset %d\", offset)\n\t\t}\n\t\t// update the offset\n\t\toffset += tagLen","sourceCodeStart":100,"sourceCodeEnd":136,"githubUrl":"https://github.com/canopy-network/canopy/blob/ee8197d91dd410f6592cb650a94c925ee6dc8bad/lib/codec/codec.go#L100-L136","documentation":"If the scan completes without finding the requested field number, GetRawProtoField returns ErrFieldNotFound wrapped with the field number. Per the library docs, in proto3 an absent scalar field equals its zero value, so this is often expected behavior rather than corruption — callers are expected to check with errors.Is.","triggerScenarios":"GetRawProtoField (directly, or via entryKeyOrZero / BytesToBlockHash) on a message whose serialization omits the requested field — proto3 zero-valued scalars, unset optional fields, or a wrong field number passed by the caller.","commonSituations":"Proto3 default-zero fields (e.g. Pool{Id:0}, Account{Address:nil}) not emitted on the wire; asking for a field number from a different message version; messages serialized by an older schema without that field.","solutions":["Check for this error with errors.Is(err, codec.ErrFieldNotFound) and treat the field as its zero value when appropriate.","Verify the field number matches the current .proto definition of the message.","If the field must always exist, use proto2-style optional/required semantics or explicitly set the field before marshaling so it appears on the wire."],"exampleFix":"// before\nraw, err := codec.GetRawProtoField(data, 1)\nif err != nil { return err }\n// after\nraw, err := codec.GetRawProtoField(data, 1)\nif errors.Is(err, codec.ErrFieldNotFound) {\n    return zeroValue, nil // proto3 zero-valued field\n}\nif err != nil { return err }","handlingStrategy":"fallback","validationCode":"var msg pb.Event\nif err := proto.Unmarshal(data, &msg); err != nil { return err }\n// check proto3 field presence via getter/oneof or optional before raw extraction","typeGuard":null,"tryCatchPattern":"raw, err := codec.GetRawProtoField(data, fieldNum)\nif errors.Is(err, codec.ErrFieldNotFound) {\n    return zeroValue, nil // proto3 zero-valued scalar: treat as empty\n}\nif err != nil { return err }","preventionTips":["Always use errors.Is(err, codec.ErrFieldNotFound) rather than string matching.","Remember proto3 omits zero-valued scalars from the wire; design callers accordingly.","Keep field numbers in sync with the .proto (use generated constants)."],"tags":["protobuf","wire-format","field-not-found","proto3"],"backgroundTag":"record-not-found","analyzedSha":"ee8197d91dd410f6592cb650a94c925ee6dc8bad","analyzedAt":"2026-09-06T09:30:15.973Z","contentChangedAt":"2026-09-06T09:30:15.973Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}