google/ExoPlayer · error · IllegalArgumentException

The item must specify its mimeType

Error message

The item must specify its mimeType

What it means

IllegalArgumentException thrown by DefaultMediaItemConverter.toMediaQueueItem when mediaItem.localConfiguration.mimeType is null. The Cast SDK requires a content type for MediaInfo, and unlike a player pipeline the Cast route has no sniffing step, so the item must carry an explicit MIME type. The converter also requires localConfiguration itself (non-null check above), i.e. a concrete URI.

Source

Thrown at extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/DefaultMediaItemConverter.java:101

        metadataBuilder.setComposer(metadata.getString(MediaMetadata.KEY_COMPOSER));
      }
      if (metadata.containsKey(MediaMetadata.KEY_DISC_NUMBER)) {
        metadataBuilder.setDiscNumber(metadata.getInt(MediaMetadata.KEY_DISC_NUMBER));
      }
      if (metadata.containsKey(MediaMetadata.KEY_TRACK_NUMBER)) {
        metadataBuilder.setTrackNumber(metadata.getInt(MediaMetadata.KEY_TRACK_NUMBER));
      }
    }
    // `mediaQueueItem` came from `toMediaQueueItem()` so the custom JSON data must be set.
    return getMediaItem(
        Assertions.checkNotNull(mediaInfo.getCustomData()), metadataBuilder.build());
  }

  @Override
  public MediaQueueItem toMediaQueueItem(MediaItem mediaItem) {
    Assertions.checkNotNull(mediaItem.localConfiguration);
    if (mediaItem.localConfiguration.mimeType == null) {
      throw new IllegalArgumentException("The item must specify its mimeType");
    }
    MediaMetadata metadata =
        new MediaMetadata(
            MimeTypes.isAudio(mediaItem.localConfiguration.mimeType)
                ? MediaMetadata.MEDIA_TYPE_MUSIC_TRACK
                : MediaMetadata.MEDIA_TYPE_MOVIE);
    if (mediaItem.mediaMetadata.title != null) {
      metadata.putString(MediaMetadata.KEY_TITLE, mediaItem.mediaMetadata.title.toString());
    }
    if (mediaItem.mediaMetadata.subtitle != null) {
      metadata.putString(MediaMetadata.KEY_SUBTITLE, mediaItem.mediaMetadata.subtitle.toString());
    }
    if (mediaItem.mediaMetadata.artist != null) {
      metadata.putString(MediaMetadata.KEY_ARTIST, mediaItem.mediaMetadata.artist.toString());
    }
    if (mediaItem.mediaMetadata.albumArtist != null) {
      metadata.putString(
          MediaMetadata.KEY_ALBUM_ARTIST, mediaItem.mediaMetadata.albumArtist.toString());

View on GitHub (pinned to dd430f7053)

Solutions

  1. Set an explicit MIME type when building every castable item: MediaItem.Builder().setUri(...).setMimeType(MimeTypes.VIDEO_MP4)
  2. Derive the type from the URI extension or your own manifest metadata when the source data lacks it
  3. Use a custom MediaItemConverter if you must supply the type at conversion time rather than on every item
  4. Guard before conversion: reject or enrich items whose localConfiguration.mimeType is null instead of crashing

Example fix

// before
MediaItem item = new MediaItem.Builder().setUri(videoUrl).build();
MediaQueueItem queueItem = converter.toMediaQueueItem(item); // throws

// after
MediaItem item = new MediaItem.Builder()
    .setUri(videoUrl)
    .setMimeType(videoUrl.endsWith(".m3u8") ? MimeTypes.APPLICATION_M3U8 : MimeTypes.VIDEO_MP4)
    .build();
MediaQueueItem queueItem = converter.toMediaQueueItem(item);
Defensive patterns

Strategy: validation

Validate before calling

MediaItem safeForCast(MediaItem item, String uri) {
  MediaItem.Builder b = item.buildUpon();
  if (item.localConfiguration == null
      || item.localConfiguration.mimeType == null) {
    b.setMimeType(guessMimeType(uri)); // e.g. from extension: .mpd/.m3u8/.mp4/.mp3
  }
  return b.build();
}

static String guessMimeType(String uri) {
  if (uri.endsWith(".m3u8")) return MimeTypes.APPLICATION_M3U8;
  if (uri.endsWith(".mpd")) return MimeTypes.APPLICATION_MPD;
  if (uri.endsWith(".mp4")) return MimeTypes.VIDEO_MP4;
  return MimeTypes.VIDEO_MP4; // sensible default; adjust to your catalog
}

Try / catch

try {
  MediaQueueItem queueItem = converter.toMediaQueueItem(item);
} catch (IllegalArgumentException e) {
  // item missing mimeType or localConfiguration: enrich and retry once
  item = item.buildUpon().setMimeType(MimeTypes.VIDEO_MP4).build();
  queueItem = converter.toMediaQueueItem(item);
}

Prevention

When it happens

Trigger: Building a MediaItem with only setUri() and passing it to a MediaItemConverter for cast queuing; MediaItem built from a MediaMetadata-only source; URI schemes where ExoPlayer would infer the type locally (progressive/adaptive) so the developer never set a MIME type until casting.

Common situations: App plays fine locally but crashes when the cast button routes the same MediaItem; items created from database rows with uri only; migrating to Media3 where setMimeType moved under RequestMetadata/LocalConfiguration.

Related errors


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