pion/webrtc · error

%w: expected %q, got %q

Error message

%w: expected %q, got %q

What it means

validateOpusTagsHeader rejects a payload whose first 8 bytes are not the 'OpusTags' magic string. ParseOpusTags only parses Opus comment headers, so any other header type (e.g. 'OpusHead') or garbage bytes trigger this wrapped errBadOpusTagsSignature error, reporting expected vs received magic.

Source

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

	userComments, err := parseUserComments(payload, vendorEnd, u32Size)
	if err != nil {
		return nil, err
	}

	return &OpusTags{
		Vendor:       vendor,
		UserComments: userComments,
	}, nil
}

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)
	}

View on GitHub (pinned to 8c25dc09fa)

Solutions

  1. Identify the correct packet: check bytes.HasPrefix(payload, []byte("OpusTags")) before calling ParseOpusTags and route 'OpusHead' packets to ParseOpusHead instead.
  2. Re-scan the stream to locate the actual OpusTags packet (usually the second packet of the first logical stream).
  3. Handle errors.Is(err, ErrBadOpusTagsSignature) at the call site and skip non-tags packets rather than aborting.

Example fix

// before
tags, err := oggreader.ParseOpusTags(packet) // may be OpusHead packet
// after
if bytes.HasPrefix(packet, []byte("OpusTags")) {
    tags, err = oggreader.ParseOpusTags(packet)
}
Defensive patterns

Strategy: type-guard

Validate before calling

if bytes.HasPrefix(payload, []byte("OpusTags")) {
    tags, err := oggreader.ParseOpusTags(payload)
} else if bytes.HasPrefix(payload, []byte("OpusHead")) {
    head, err := oggreader.ParseOpusHead(payload)
}

Type guard

func isOpusTagsPacket(p []byte) bool {
    return len(p) >= 8 && string(p[:8]) == "OpusTags"
}

Try / catch

tags, err := oggreader.ParseOpusTags(payload)
var sigErr *? // sentinel-based check:
if errors.Is(err, oggreader.ErrBadOpusTagsSignature) {
    // wrong packet type: route to ParseOpusHead or skip
}

Prevention

When it happens

Trigger: Calling ParseOpusTags on the OpusHead (identification) packet, on an audio data packet, or on any non-comment-header packet; byte offsets misaligned so payload[:8] is not the magic.

Common situations: Iterating an Ogg stream and feeding every packet to ParseOpusTags instead of only the second logical-stream packet; stream starts mid-file so the ID header was missed and packets are misidentified; corrupted first 8 bytes of the tags packet.

Related errors


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