pion/webrtc · error

%w: payload too short for vendor string

Error message

%w: payload too short for vendor string

What it means

parseVendorString fails when the 32-bit little-endian vendor string length read from the payload exceeds the bytes actually available after the fixed header. The declared vendor string would run past the end of the packet, so the payload is corrupt or truncated; the wrapped errBadOpusTagsSignature sentinel is returned.

Source

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

}

func validateOpusTagsHeader(payload []byte, minHeaderLen int) error {
	if len(payload) < minHeaderLen {
		return fmt.Errorf("%w: payload too short", errBadOpusTagsSignature)
	}

	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)

View on GitHub (pinned to 8c25dc09fa)

Solutions

  1. Re-acquire or re-extract the file/stream; the tags packet is malformed at the source, so re-download or re-mux with a known-good encoder (e.g. ffmpeg).
  2. Verify the Ogg page was fully reassembled (concatenate all pages of the packet) before parsing; do not parse a single short page of a large tags header.
  3. At the call site, match errors.Is(err, ErrBadOpusTagsSignature) and reject/skip the metadata instead of indexing blindly.

Example fix

// before
tags, err := oggreader.ParseOpusTags(singlePage[:pageLen])
// after
full := assembleFullPacket(pages) // concatenate all Ogg pages of the packet
tags, err = oggreader.ParseOpusTags(full)
Defensive patterns

Strategy: try-catch

Validate before calling

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

Try / catch

tags, err := oggreader.ParseOpusTags(payload)
if errors.Is(err, oggreader.ErrBadOpusTagsSignature) {
    log.Warn("malformed OpusTags vendor string; skipping metadata")
    return nil, nil // degrade gracefully
}

Prevention

When it happens

Trigger: ParseOpusTags (or the parseVendorString helper in tests) on a payload whose vendor-length field at offset 8 declares more bytes than len(payload)-minHeaderLen provides — e.g. vendorLen claims 1000 bytes in a 30-byte payload.

Common situations: Maliciously or accidentally malformed OpusTags metadata; truncation during download or stream reassembly; a writer bug emitting a wrong length prefix; fuzzing or parsing untrusted media.

Related errors


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