DefaultPreloadManager NPE in maybeClearPreloadMediaSource when TargetPreloadStatusControl returns null
@tianyif is already working on this.
Since Apr 2, 2026.
- Dominant language
- Java
- Stars
- 3k
- Forks
- 955
- Avg merge
- 12d 14h
- Merged PRs (30d)
- 2
Description
Description
DefaultPreloadManager.setCurrentPlayingIndex() throws a NullPointerException when TargetPreloadStatusControl.getTargetPreloadStatus() returns null for any item in the preload window.
The NPE occurs on every call to setCurrentPlayingIndex(), making the preload system non-functional despite null being a documented valid return value ("don't preload this item").
Version
- Media3 1.9.2 (verified)
- Also verified present in 1.10.0 source and
mainbranch
Stack trace
java.lang.NullPointerException: Attempt to read from field 'int
androidx.media3.exoplayer.source.preload.DefaultPreloadManager$PreloadStatus.stage'
on a null object reference in method 'void
androidx.media3.exoplayer.source.preload.DefaultPreloadManager.maybeClearPreloadMediaSource(
androidx.media3.exoplayer.source.preload.PreloadMediaSource,
androidx.media3.exoplayer.source.preload.DefaultPreloadManager$PreloadStatus)'
at DefaultPreloadManager.maybeClearPreloadMediaSource(DefaultPreloadManager.java:589)
at DefaultPreloadManager.preloadMediaSourceHolderInternal(DefaultPreloadManager.java:567)
at DefaultPreloadManager.preloadMediaSourceHolderInternal(DefaultPreloadManager.java:70)
at BasePreloadManager.maybeStartPreloadingNextSourceHolder(BasePreloadManager.java:586)
at BasePreloadManager.invalidate(BasePreloadManager.java:209)
at DefaultPreloadManager$SimpleRankingDataComparator.setCurrentPlayingIndex(DefaultPreloadManager.java:661)
at DefaultPreloadManager.setCurrentPlayingIndex(DefaultPreloadManager.java:544)
Root cause
BasePreloadManager.maybeStartPreloadingNextSourceHolder() calls targetPreloadStatusControl.getTargetPreloadStatus(rankingData), which may return null per its contract. The null result is passed directly to DefaultPreloadManager.preloadMediaSourceHolderInternal(holder, targetPreloadStatus), then to maybeClearPreloadMediaSource(preloadMediaSource, targetPreloadStatus), which accesses targetPreloadStatus.stage without a null check.
Reproduction
- Create a
DefaultPreloadManagerwith aTargetPreloadStatusControlthat returnsnullfor some items (e.g., the currently playing item at distance 0) - Add multiple items via
add() - Call
setCurrentPlayingIndex()— NPE every time
Suggested fix
Add a null guard in BasePreloadManager.maybeStartPreloadingNextSourceHolder():
this.targetPreloadStatusOfCurrentPreloadingSource =
targetPreloadStatusControl.getTargetPreloadStatus(preloadingHolder.rankingData);
if (this.targetPreloadStatusOfCurrentPreloadingSource == null) {
return false; // skip this source
}
preloadMediaSourceHolderInternal(
preloadingHolder, targetPreloadStatusOfCurrentPreloadingSource);
Workaround
Never return null from getTargetPreloadStatus(). Use PRELOAD_STATUS_SOURCE_PREPARED (lightest tier) for items that should not be preloaded. The preload manager handles this status correctly.
Device info
- Pixel 7a, Android 15 (SDK 36)
- HLS content with fMP4/CMAF segments
- 4-tier preload strategy (specifiedRangeLoaded → TRACKS_SELECTED → SOURCE_PREPARED)
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.