{"record":{"id":"2f317906d050800c","repo":"AlexxIT/go2rtc","slug":"tlv8-unmarshal-zero-data","errorCode":null,"errorMessage":"tlv8: unmarshal zero data","messagePattern":"tlv8: unmarshal zero data","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/hap/tlv8/tlv8.go","lineNumber":196,"sourceCode":"\tvar data []byte\n\tvar err error\n\n\tif n > 0 {\n\t\tdata = make([]byte, n)\n\t\t_, err = io.ReadFull(r, data)\n\t} else {\n\t\tdata, err = io.ReadAll(r)\n\t}\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn Unmarshal(data, v)\n}\n\nfunc Unmarshal(data []byte, v any) error {\n\tif len(data) == 0 {\n\t\treturn errors.New(\"tlv8: unmarshal zero data\")\n\t}\n\n\tvalue := reflect.ValueOf(v)\n\tkind := value.Kind()\n\n\tif kind != reflect.Pointer {\n\t\treturn errors.New(\"tlv8: value should be pointer: \" + kind.String())\n\t}\n\n\tvalue = value.Elem()\n\tkind = value.Kind()\n\n\tif kind == reflect.Interface {\n\t\tvalue = value.Elem()\n\t\tkind = value.Kind()\n\t}\n\n\tswitch kind {","sourceCodeStart":178,"sourceCodeEnd":214,"githubUrl":"https://github.com/AlexxIT/go2rtc/blob/c245815e75e2a5fd60b4290f12bfc04e55a984d3/pkg/hap/tlv8/tlv8.go#L178-L214","documentation":"tlv8.Unmarshal rejects empty input: TLV8 data must contain at least one tag/length/value record, so len(data)==0 is treated as a decoding error rather than leaving the target zero-valued. It protects callers from silently treating an empty body as a valid message.","triggerScenarios":"Calling tlv8.Unmarshal(nil, &v), tlv8.Unmarshal([]byte{}, &v), or via UnmarshalBase64 with an empty/whitespace-only string, or UnmarshalReader when the reader yields zero bytes (e.g. HTTP request with Content-Length 0 or an empty body).","commonSituations":"Peer sent an empty HTTP body with a TLV8 content type; reading a truncated response; decoding an empty base64 field from persisted state; off-by-one slicing that produced an empty slice; a client sending a keep-alive/empty POST that the server tries to decode.","solutions":["Check len(data) (or the decoded base64 string) is non-zero before calling Unmarshal and treat empty as a protocol/transport-level problem.","Inspect why the producer sent zero bytes: truncated read, empty request body, or upstream error — fix at the source.","If an empty payload is legitimately meaningful in your protocol, guard it in caller code instead of routing it through Unmarshal.","For UnmarshalReader, verify Content-Length > 0 or that io.ReadAll returned data before decoding."],"exampleFix":"// before\nvar msg message\nif err := tlv8.UnmarshalBase64(req.EncryptedData, &msg); err != nil { return err } // fails on \"\"\n\n// after\nif req.EncryptedData == \"\" {\n    return errors.New(\"empty tlv8 payload from peer\")\n}\nvar msg message\nif err := tlv8.UnmarshalBase64(req.EncryptedData, &msg); err != nil { return err }","handlingStrategy":"validation","validationCode":"func safeUnmarshal(data []byte, v any) error {\n    if len(data) == 0 {\n        return errors.New(\"peer sent empty tlv8 payload\")\n    }\n    return tlv8.Unmarshal(data, v)\n}","typeGuard":null,"tryCatchPattern":"if err := tlv8.UnmarshalReader(req.Body, req.ContentLength, &msg); err != nil {\n    if strings.Contains(err.Error(), \"zero data\") {\n        return errors.New(\"empty TLV8 body from peer; check request format\")\n    }\n    return err\n}","preventionTips":["Check len(data)/Content-Length > 0 before decoding TLV8 bodies.","Handle empty peer payloads as transport errors, not decode retries.","When decoding persisted base64 fields, treat empty strings as absent data."],"tags":["tlv8","unmarshal","empty-input","protocol"],"backgroundTag":"empty-required-field","analyzedSha":"c245815e75e2a5fd60b4290f12bfc04e55a984d3","analyzedAt":"2026-09-07T11:47:02.965Z","contentChangedAt":"2026-09-07T11:47:02.965Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}