{"record":{"id":"e8d75d6f6b913d99","repo":"pion/webrtc","slug":"w-payload-too-short-for-vendor-comment-count","errorCode":null,"errorMessage":"%w: payload too short for vendor+comment count","messagePattern":"%w: payload too short for vendor\\+comment count","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/media/oggreader/oggreader.go","lineNumber":434,"sourceCode":"\tgot := HeaderType(payload[:8])\n\tif got != HeaderOpusTags {\n\t\treturn fmt.Errorf(\"%w: expected %q, got %q\", errBadOpusTagsSignature, HeaderOpusTags, got)\n\t}\n\n\treturn nil\n}\n\nfunc parseVendorString(payload []byte, headerMagicLen, u32Size, minHeaderLen int) (string, int, error) {\n\tvendorLen32 := binary.LittleEndian.Uint32(payload[headerMagicLen : headerMagicLen+u32Size])\n\tif int(vendorLen32) > len(payload)-minHeaderLen {\n\t\treturn \"\", 0, fmt.Errorf(\"%w: payload too short for vendor string\", errBadOpusTagsSignature)\n\t}\n\tvendorLen := int(vendorLen32)\n\n\tvendorStart := headerMagicLen + u32Size\n\tvendorEnd := vendorStart + vendorLen\n\tif vendorEnd+u32Size > len(payload) {\n\t\treturn \"\", 0, fmt.Errorf(\"%w: payload too short for vendor+comment count\", errBadOpusTagsSignature)\n\t}\n\n\tvendor := string(payload[vendorStart:vendorEnd])\n\n\treturn vendor, vendorEnd, nil\n}\n\nfunc parseUserComments(payload []byte, vendorEnd, u32Size int) ([]UserComment, error) {\n\tuserCommentCount32 := binary.LittleEndian.Uint32(payload[vendorEnd : vendorEnd+u32Size])\n\tif int(userCommentCount32) > (len(payload)-vendorEnd)/u32Size {\n\t\treturn nil, fmt.Errorf(\"%w: unreasonable comment count\", errBadOpusTagsSignature)\n\t}\n\tuserCommentCount := int(userCommentCount32)\n\n\tpos := vendorEnd + u32Size\n\tuserComments := make([]UserComment, userCommentCount)\n\n\tfor i := range userComments {","sourceCodeStart":416,"sourceCodeEnd":452,"githubUrl":"https://github.com/pion/webrtc/blob/8c25dc09fa9e7c09aac4309ead88093d760432b0/pkg/media/oggreader/oggreader.go#L416-L452","documentation":"parseVendorString also verifies that room remains after the vendor string for the 4-byte user-comment count. If vendorStart+vendorLen plus the 4-byte count field extends beyond the payload, the packet is truncated after the vendor string and the wrapped errBadOpusTagsSignature sentinel is returned.","triggerScenarios":"ParseOpusTags on a payload where the vendor string occupies bytes up to (or past) the end, leaving no 4-byte comment count — e.g. a header with a correct magic and vendor length but cut off before the following uint32.","commonSituations":"Tests simulating a missing comment count (TestParseVendorStringMissingCommentCount); truncated comment headers from partial writes or interrupted downloads; hand-crafted/fuzzed OpusTags packets missing the trailing fields.","solutions":["Ensure the full OpusTags packet, including the comment count (and comment entries), is present before parsing; concatenate all pages of the header packet.","Re-generate or re-download the file; the source stream is truncated, so fix the writer or re-mux the media.","At the call site, check errors.Is(err, ErrBadOpusTagsSignature) and treat the metadata as invalid rather than proceeding."],"exampleFix":"// before\ntags, err := oggreader.ParseOpusTags(payload[:8+4+vendorLen]) // count field cut off\n// after\nif len(payload) >= 8+4+vendorLen+4 {\n    tags, err = oggreader.ParseOpusTags(payload)\n}","handlingStrategy":"validation","validationCode":"if len(payload) >= 12 {\n    vendorLen := int(binary.LittleEndian.Uint32(payload[8:12]))\n    if 12+vendorLen+4 <= len(payload) {\n        tags, err := oggreader.ParseOpusTags(payload)\n    }\n}","typeGuard":"func hasVendorAndCommentCount(p []byte) bool {\n    if len(p) < 12 {\n        return false\n    }\n    vendorLen := int(binary.LittleEndian.Uint32(p[8:12]))\n    return 12+vendorLen+4 <= len(p)\n}","tryCatchPattern":"tags, err := oggreader.ParseOpusTags(payload)\nif errors.Is(err, oggreader.ErrBadOpusTagsSignature) {\n    // header truncated before comment count: skip metadata or re-fetch stream\n}","preventionTips":["Ensure the entire OpusTags packet (magic + vendor + comment count + comments) is buffered before parsing.","Validate that streams end with the EOS-flagged Ogg page; treat missing EOS as suspect data.","Handle partial writes from network sources by buffering until the packet is complete.","Add regression tests (like TestParseVendorStringMissingCommentCount) covering truncated headers."],"tags":["go","ogg","opus","truncated-input","length-check"],"backgroundTag":"payload-too-short","analyzedSha":"8c25dc09fa9e7c09aac4309ead88093d760432b0","analyzedAt":"2026-09-03T21:56:56.182Z","contentChangedAt":"2026-09-03T21:56:56.182Z","schemaVersion":2},"datasetVersion":"2026-09-11T07:07:21.782Z"}