google/ExoPlayer · error · OpusDecoderException
Invalid header, missing stream map
Error message
Invalid header, missing stream map
What it means
The Opus header declares channel mapping family 0 (byte 18 == 0), which supports at most stereo via the default layout, but the channel count read from the header is > 2. Family 0 headers carry no stream map, so the decoder cannot map more than 2 channels and rejects the header as internally inconsistent.
Source
Thrown at extensions/opus/src/main/java/com/google/android/exoplayer2/ext/opus/OpusDecoder.java:127
skipSamples = preSkipSamples;
byte[] headerBytes = initializationData.get(0);
if (headerBytes.length < 19) {
throw new OpusDecoderException("Invalid header length");
}
channelCount = getChannelCount(headerBytes);
if (channelCount > 8) {
throw new OpusDecoderException("Invalid channel count: " + channelCount);
}
int gain = readSignedLittleEndian16(headerBytes, 16);
byte[] streamMap = new byte[8];
int numStreams;
int numCoupled;
if (headerBytes[18] == 0) { // Channel mapping
// If there is no channel mapping, use the defaults.
if (channelCount > 2) { // Maximum channel count with default layout.
throw new OpusDecoderException("Invalid header, missing stream map");
}
numStreams = 1;
numCoupled = (channelCount == 2) ? 1 : 0;
streamMap[0] = 0;
streamMap[1] = 1;
} else {
if (headerBytes.length < 21 + channelCount) {
throw new OpusDecoderException("Invalid header length");
}
// Read the channel mapping.
numStreams = headerBytes[19] & 0xFF;
numCoupled = headerBytes[20] & 0xFF;
System.arraycopy(headerBytes, 21, streamMap, 0, channelCount);
}
nativeDecoderContext =
opusInit(SAMPLE_RATE, channelCount, numStreams, numCoupled, gain, streamMap);
if (nativeDecoderContext == 0) {
throw new OpusDecoderException("Failed to initialize decoder");View on GitHub (pinned to dd430f7053)
Solutions
- Re-encode/remux the file so multichannel Opus uses channel mapping family 1 (byte 18 = 1) with a proper stream map of 21 + channelCount bytes.
- If you build the header yourself, either cap channels at 2 with family 0, or emit family >= 1 plus numStreams, numCoupled and the per-channel mapping table.
- Reject the track at track-selection time if the header is inconsistent (family 0 and channels > 2).
Example fix
// before (hand-built header) header[9] = 6; // 6 channels header[18] = 0; // family 0 -> decoder throws // after header[9] = 6; header[18] = 1; // family 1 header[19] = 4; // numStreams header[20] = 2; // numCoupled // append 6 mapping bytes at offset 21...
Defensive patterns
Strategy: validation
Validate before calling
int channels = h[9] & 0xFF;
int family = h[18] & 0xFF;
if (family == 0 && channels > 2) { /* inconsistent header: reject track */ } Prevention
- When authoring headers, pair multichannel counts with mapping family >= 1.
- Prefer files produced by libopus/ffmpeg rather than custom muxers.
- Add header-consistency checks in ingest pipelines.
When it happens
Trigger: initializationData[0][18] == 0 while the channel count byte (offset 9) is 3-8. Produced by malformed encoders or hand-authored headers that combine a multichannel count with mapping family 0.
Common situations: Files produced by broken transcoders or hand-edited headers; constructing Opus initializationData manually and forgetting to emit the full channel mapping table for multichannel audio.
Related errors
- Invalid header length
- Invalid channel count: ${channelCount}
- Failed to load decoder native libraries
- Failed to initialize decoder
- Error instantiating Opus extension
AI-assisted analysis of google/ExoPlayer@dd430f7053 (2026-08-14).
Data as JSON: /api/errors/e99cf5bad8d5011e.
Report an issue: GitHub.