pion/webrtc · error

%w: payload too short for vendor+comment count

Error message

%w: payload too short for vendor+comment count

What it means

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.

Source

Thrown at pkg/media/oggreader/oggreader.go:434

	got := HeaderType(payload[:8])
	if got != HeaderOpusTags {
		return fmt.Errorf("%w: expected %q, got %q", errBadOpusTagsSignature, HeaderOpusTags, got)
	}

	return nil
}

func parseVendorString(payload []byte, headerMagicLen, u32Size, minHeaderLen int) (string, int, error) {
	vendorLen32 := binary.LittleEndian.Uint32(payload[headerMagicLen : headerMagicLen+u32Size])
	if int(vendorLen32) > len(payload)-minHeaderLen {
		return "", 0, fmt.Errorf("%w: payload too short for vendor string", errBadOpusTagsSignature)
	}
	vendorLen := int(vendorLen32)

	vendorStart := headerMagicLen + u32Size
	vendorEnd := vendorStart + vendorLen
	if vendorEnd+u32Size > len(payload) {
		return "", 0, fmt.Errorf("%w: payload too short for vendor+comment count", errBadOpusTagsSignature)
	}

	vendor := string(payload[vendorStart:vendorEnd])

	return vendor, vendorEnd, nil
}

func parseUserComments(payload []byte, vendorEnd, u32Size int) ([]UserComment, error) {
	userCommentCount32 := binary.LittleEndian.Uint32(payload[vendorEnd : vendorEnd+u32Size])
	if int(userCommentCount32) > (len(payload)-vendorEnd)/u32Size {
		return nil, fmt.Errorf("%w: unreasonable comment count", errBadOpusTagsSignature)
	}
	userCommentCount := int(userCommentCount32)

	pos := vendorEnd + u32Size
	userComments := make([]UserComment, userCommentCount)

	for i := range userComments {

View on GitHub (pinned to 8c25dc09fa)

Solutions

  1. Ensure the full OpusTags packet, including the comment count (and comment entries), is present before parsing; concatenate all pages of the header packet.
  2. Re-generate or re-download the file; the source stream is truncated, so fix the writer or re-mux the media.
  3. At the call site, check errors.Is(err, ErrBadOpusTagsSignature) and treat the metadata as invalid rather than proceeding.

Example fix

// before
tags, err := oggreader.ParseOpusTags(payload[:8+4+vendorLen]) // count field cut off
// after
if len(payload) >= 8+4+vendorLen+4 {
    tags, err = oggreader.ParseOpusTags(payload)
}
Defensive patterns

Strategy: validation

Validate before calling

if len(payload) >= 12 {
    vendorLen := int(binary.LittleEndian.Uint32(payload[8:12]))
    if 12+vendorLen+4 <= len(payload) {
        tags, err := oggreader.ParseOpusTags(payload)
    }
}

Type guard

func hasVendorAndCommentCount(p []byte) bool {
    if len(p) < 12 {
        return false
    }
    vendorLen := int(binary.LittleEndian.Uint32(p[8:12]))
    return 12+vendorLen+4 <= len(p)
}

Try / catch

tags, err := oggreader.ParseOpusTags(payload)
if errors.Is(err, oggreader.ErrBadOpusTagsSignature) {
    // header truncated before comment count: skip metadata or re-fetch stream
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of pion/webrtc@8c25dc09fa (2026-09-03). Data as JSON: /api/errors/e8d75d6f6b913d99. Report an issue: GitHub.