androidx / androidx/media

DefaultPreloadManager NPE in maybeClearPreloadMediaSource when TargetPreloadStatusControl returns null

Open
#3,155 1 comment 1 reaction 1 assignee View on GitHub

@tianyif is already working on this.

Since Apr 2, 2026.

documentation candidate
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 main branch

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

  1. Create a DefaultPreloadManager with a TargetPreloadStatusControl that returns null for some items (e.g., the currently playing item at distance 0)
  2. Add multiple items via add()
  3. 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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.