google/ExoPlayer · error · FlacDecoderException

Failed to decode StreamInfo

Error message

Failed to decode StreamInfo

What it means

FlacDecoderException wrapping a ParserException thrown when decoderJni.decodeStreamMetadata() cannot parse the bytes set from initializationData[0] as a FLAC STREAMINFO block. Unlike the length check, this means one entry existed but its contents are not a valid stream-info header (wrong bytes, wrong offset, or corrupt header).

Source

Thrown at extensions/flac/src/main/java/com/google/android/exoplayer2/ext/flac/FlacDecoder.java:75

   *     which is the flac file header.
   * @throws FlacDecoderException Thrown if an exception occurs when initializing the decoder.
   */
  public FlacDecoder(
      int numInputBuffers,
      int numOutputBuffers,
      int maxInputBufferSize,
      List<byte[]> initializationData)
      throws FlacDecoderException {
    super(new DecoderInputBuffer[numInputBuffers], new SimpleDecoderOutputBuffer[numOutputBuffers]);
    if (initializationData.size() != 1) {
      throw new FlacDecoderException("Initialization data must be of length 1");
    }
    decoderJni = new FlacDecoderJni();
    decoderJni.setData(ByteBuffer.wrap(initializationData.get(0)));
    try {
      streamMetadata = decoderJni.decodeStreamMetadata();
    } catch (ParserException e) {
      throw new FlacDecoderException("Failed to decode StreamInfo", e);
    } catch (IOException e) {
      // Never happens.
      throw new IllegalStateException(e);
    }

    int initialInputBufferSize =
        maxInputBufferSize != Format.NO_VALUE ? maxInputBufferSize : streamMetadata.maxFrameSize;
    setInitialInputBufferSize(initialInputBufferSize);
  }

  @Override
  public String getName() {
    return "libflac";
  }

  @Override
  protected DecoderInputBuffer createInputBuffer() {
    return new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_NORMAL);

View on GitHub (pinned to dd430f7053)

Solutions

  1. Verify initializationData[0] is exactly the STREAMINFO block: expect 34 bytes starting after the 'fLaC' magic with block header 0x00 (last-block=0, type=0)
  2. Re-download or re-mux the source file; validate it with 'flac -t' or ffprobe outside the app
  3. If writing a custom extractor, use FlacConstants and the library's own FrameReader/metadata parsing rather than slicing manually
  4. Catch FlacDecoderException at renderer construction and surface a 'corrupt file' message or fall back to platform decoding

Example fix

// before: passing the whole file header (magic + block header included)
List<byte[]> init = Collections.singletonList(first38Bytes);
new FlacDecoder(numIn, numOut, maxIn, init); // ParserException: bad StreamInfo

// after: pass only the 34-byte STREAMINFO payload
List<byte[]> init = Collections.singletonList(
    Arrays.copyOfRange(header, 4 /* magic */ + 4 /* block header */, 4 + 4 + 34));
new FlacDecoder(numIn, numOut, maxIn, init);
Defensive patterns

Strategy: try-catch

Validate before calling

boolean looksLikeStreamInfo(byte[] block) {
  return block != null && block.length == 34
      && block[0] != 0; // sampleRate bits (top 20 bits) must be non-zero for real STREAMINFO
}

if (!looksLikeStreamInfo(format.initializationData.get(0))) {
  // header bytes are wrong/corrupt: fail with a clear message before decoder init
}

Try / catch

try {
  decoder = new FlacDecoder(numIn, numOut, maxIn, format.initializationData);
} catch (FlacDecoderException e) {
  if (e.getMessage() != null && e.getMessage().contains("StreamInfo")) {
    // header block invalid: mark source as corrupt and skip / re-download
    markSourceCorrupt(uri);
  } else {
    throw e;
  }
}

Prevention

When it happens

Trigger: initializationData[0] contains bytes that are not the 34-byte STREAMINFO block (e.g. an ID3 tag remnant, the whole file header including the magic, or a partial read); truncated FLAC file; header bytes byte-swapped or re-encoded by an upstream transform.

Common situations: Corrupt downloads; FLAC files with non-standard prepended metadata; custom extractors passing the wrong slice of the header; files that fail sniffing and get misparsed as FLAC.

Understand the failure class

Related errors


AI-assisted analysis of google/ExoPlayer@dd430f7053 (2026-08-14). Data as JSON: /api/errors/6f31c61849c23744. Report an issue: GitHub.