{"record":{"id":"08be82fb8b5adfd2","repo":"google/ExoPlayer","slug":"cannot-read-frame-at-position-lastdecodeposition","errorCode":null,"errorMessage":"Cannot read frame at position ${lastDecodePosition}","messagePattern":"Cannot read frame at position (.+?)","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"extensions/flac/src/main/java/com/google/android/exoplayer2/ext/flac/FlacExtractor.java","lineNumber":154,"sourceCode":"  public int read(final ExtractorInput input, PositionHolder seekPosition) throws IOException {\n    if (input.getPosition() == 0 && !id3MetadataDisabled && id3Metadata == null) {\n      id3Metadata = FlacMetadataReader.peekId3Metadata(input, /* parseData= */ true);\n    }\n\n    FlacDecoderJni decoderJni = initDecoderJni(input);\n    try {\n      decodeStreamMetadata(input);\n\n      if (binarySearchSeeker != null && binarySearchSeeker.isSeeking()) {\n        return handlePendingSeek(input, seekPosition, outputBuffer, outputFrameHolder, trackOutput);\n      }\n\n      ByteBuffer outputByteBuffer = outputFrameHolder.byteBuffer;\n      long lastDecodePosition = decoderJni.getDecodePosition();\n      try {\n        decoderJni.decodeSampleWithBacktrackPosition(outputByteBuffer, lastDecodePosition);\n      } catch (FlacDecoderJni.FlacFrameDecodeException e) {\n        throw new IOException(\"Cannot read frame at position \" + lastDecodePosition, e);\n      }\n      int outputSize = outputByteBuffer.limit();\n      if (outputSize == 0) {\n        return RESULT_END_OF_INPUT;\n      }\n\n      outputSample(outputBuffer, outputSize, decoderJni.getLastFrameTimestamp(), trackOutput);\n      return decoderJni.isEndOfData() ? RESULT_END_OF_INPUT : RESULT_CONTINUE;\n    } finally {\n      decoderJni.clearData();\n    }\n  }\n\n  @Override\n  public void seek(long position, long timeUs) {\n    if (position == 0) {\n      streamMetadataDecoded = false;\n    }","sourceCodeStart":136,"sourceCodeEnd":172,"githubUrl":"https://github.com/google/ExoPlayer/blob/dd430f7053a1a3958deea3ead6a0565150c06bfc/extensions/flac/src/main/java/com/google/android/exoplayer2/ext/flac/FlacExtractor.java#L136-L172","documentation":"Wraps a FlacDecoderJni.FlacFrameDecodeException raised while decoding a FLAC frame in FlacExtractor.read(), converting it into an IOException so the extractor pipeline treats it as an unrecoverable read failure for the current sample. It reports the exact stream position (lastDecodePosition) where the native decoder bailed out, which pins the failure to a specific frame in the input data.","triggerScenarios":"FlacExtractor.read() calls decoderJni.decodeSampleWithBacktrackPosition(...); if the native libflac decoder rejects the frame (CRC mismatch, malformed subframe, or a mid-stream inconsistency between the frame header and the STREAMINFO block) the JNI layer throws FlacFrameDecodeException and it is rethrown as this IOException. Common with truncated or corrupted FLAC files and with files whose STREAMINFO disagrees with actual frames.","commonSituations":"Playing a partially downloaded or bit-flipped .flac; seeking in a stream produced by a broken encoder; extractor tests feeding hand-crafted FLAC data; live/progressive streams that are truncated at the network layer.","solutions":["Verify the file plays with an independent tool (ffplay/flac -t) — if it also fails, the file is corrupted; re-rip or re-download the source.","If the file is valid, check that the data being fed is complete: for progressive/HTTP sources inspect for truncation (Content-Length vs bytes read) and for local files compare checksums.","Upgrade the FLAC extension / migrate to androidx.media3 — older libflac builds had stricter or buggier frame validation that has since been fixed.","If corruption is expected in your environment, catch IOException around player preparation and surface a user-facing 'unsupported/corrupt media' error rather than retrying indefinitely."],"exampleFix":"// before\nplayer.setMediaItem(MediaItem.fromUri(corruptFlacUri)); // PlaybackException: Cannot read frame at position ...\n\n// after\nplayer.setMediaItem(MediaItem.fromUri(corruptFlacUri));\nplayer.addListener(new Player.Listener() {\n  @Override public void onPlayerError(PlaybackException error) {\n    if (error.getErrorCode() == PlaybackException.ERROR_CODE_PARSING_CONTAINER_MALFORMED) {\n      showUserMessage(\"Corrupted FLAC file: \" + error.getMessage()); // includes frame position\n    }\n  }\n});","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// At player level:\nplayer.addListener(new Player.Listener() {\n  @Override public void onPlayerError(PlaybackException e) {\n    if (e.getErrorCode() == PlaybackException.ERROR_CODE_PARSING_CONTAINER_MALFORMED\n        && e.getMessage() != null && e.getMessage().contains(\"Cannot read frame\")) {\n      skipToNextItem(); // corrupted FLAC: do not retry the same file\n    }\n  }\n});","preventionTips":["Verify media integrity (checksums) before caching/playing.","Do not auto-retry parsing errors infinitely; classify them as permanent in DefaultLoadErrorHandlingPolicy."],"tags":["flac","extractor","corruption","parsing","io"],"backgroundTag":null,"analyzedSha":"dd430f7053a1a3958deea3ead6a0565150c06bfc","analyzedAt":"2026-08-14T12:22:02.982Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}