{"record":{"id":"32d933d4ef8701e9","repo":"AlexxIT/go2rtc","slug":"tlv8-wrong-size","errorCode":null,"errorMessage":"tlv8: wrong size: ","messagePattern":"tlv8: wrong size: ","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/hap/tlv8/tlv8.go","lineNumber":229,"sourceCode":"\t\tkind = value.Kind()\n\t}\n\n\tswitch kind {\n\tcase reflect.Slice:\n\t\treturn unmarshalSlice(data, value)\n\tcase reflect.Struct:\n\t\treturn unmarshalStruct(data, value)\n\t}\n\n\treturn errors.New(\"tlv8: not implemented: \" + kind.String())\n}\n\n// unmarshalTLV can return two types of errors:\n// - critical and then the value of []byte will be nil\n// - not critical and then []byte will contain the value\nfunc unmarshalTLV(b []byte, value reflect.Value) ([]byte, error) {\n\tif len(b) < 2 {\n\t\treturn nil, errors.New(\"tlv8: wrong size: \" + value.Type().Name())\n\t}\n\n\tt := b[0]\n\tl := int(b[1])\n\n\t// array item divider (t == 0x00 || t == 0xFF)\n\tif l == 0 {\n\t\treturn b[2:], errors.New(\"tlv8: zero item\")\n\t}\n\n\tvar v []byte\n\n\tfor {\n\t\tif len(b) < 2+l {\n\t\t\treturn nil, errors.New(\"tlv8: wrong size: \" + value.Type().Name())\n\t\t}\n\n\t\tv = append(v, b[2:2+l]...)","sourceCodeStart":211,"sourceCodeEnd":247,"githubUrl":"https://github.com/AlexxIT/go2rtc/blob/c245815e75e2a5fd60b4290f12bfc04e55a984d3/pkg/hap/tlv8/tlv8.go#L211-L247","documentation":"unmarshalTLV reads a TLV8 record that must contain at least a 1-byte tag and a 1-byte length header. If fewer than 2 bytes remain in the buffer (0 or 1 byte), the record header cannot be read, so it returns nil bytes plus this \"wrong size\" error naming the destination type. Returning nil marks the error as critical, so unmarshalStruct aborts the whole decode.","triggerScenarios":"Decoding a truncated TLV8 payload — e.g. data ending in a single stray byte after the last valid record, a payload cut off mid-record by a partial HTTP body read, or a base64 string that decodes to an odd trailing byte — passed to Unmarshal (and thus Dial/Pair/PairSetup/PairVerify).","commonSituations":"Reading a fixed-length HAP response with UnmarshalReader using a wrong `n` so the tail is truncated; base64 payload manually edited or copy-pasted incompletely; a peer sending malformed/malicious TLV8 data; concatenating payloads and losing a byte.","solutions":["Verify the input payload length is even and complete before calling Unmarshal: len(data)%2 == 0 for simple TLV8, and each record consumes 2+L bytes.","Check for truncation upstream: if using UnmarshalReader with n, confirm io.ReadFull consumed all n bytes and that n matches the actual record.","Log/reject malformed peer data at the protocol layer (HAP pairing) and restart the pairing/verification session rather than retrying the same bytes.","Validate the base64 input decodes without error and contains no stray characters before UnmarshalBase64."],"exampleFix":"// before\ntlv8.UnmarshalReader(resp.Body, -1, &out) // reads all, even truncated garbage\n\n// after\nvar n int64 = declaredLen\ndata, _ := io.ReadAll(resp.Body)\nif int64(len(data)) < n {\n    return fmt.Errorf(\"tlv8 payload truncated: got %d want %d\", len(data), n)\n}\ntlv8.Unmarshal(data, &out)","handlingStrategy":"validation","validationCode":"func validTLV8Framing(data []byte) bool {\n    for i := 0; i < len(data); {\n        if len(data)-i < 2 {\n            return false // truncated header\n        }\n        l := int(data[i+1])\n        i += 2 + l\n    }\n    return true\n}\n// call validTLV8Framing(data) before tlv8.Unmarshal(data, &out)","typeGuard":null,"tryCatchPattern":"if !validTLV8Framing(data) {\n    return errors.New(\"refusing to decode truncated tlv8 payload\")\n}\nif err := tlv8.Unmarshal(data, &out); err != nil {\n    if strings.Contains(err.Error(), \"tlv8: wrong size\") {\n        return fmt.Errorf(\"corrupt tlv8 payload from peer: %w\", err)\n    }\n    return err\n}","preventionTips":["Always read the complete transport payload (check Content-Length / io.ReadFull results) before decoding.","Pass the correct n to UnmarshalReader, or 0 to consume the whole reader.","Validate base64 inputs decode cleanly and have expected length before UnmarshalBase64.","Treat malformed TLV8 from a peer as a protocol violation: abort the session, log, and restart pairing."],"tags":["tlv8","malformed-input","truncated-data","unmarshal","go"],"backgroundTag":"invalid-argument-format","analyzedSha":"c245815e75e2a5fd60b4290f12bfc04e55a984d3","analyzedAt":"2026-09-07T11:47:02.965Z","contentChangedAt":"2026-09-07T11:47:02.965Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}