google/ExoPlayer · error · IllegalStateException

Missing implementation to handle COMMAND_RELEASE

Error message

Missing implementation to handle COMMAND_RELEASE

What it means

Default handler for Player.release() in SimpleBasePlayer: IllegalStateException thrown because handleRelease() is not overridden although COMMAND_RELEASE is available in the current State. Every command the player advertises must be backed by an implementation.

Source

Thrown at library/common/src/main/java/com/google/android/exoplayer2/SimpleBasePlayer.java:2966

   * @return A {@link ListenableFuture} indicating the completion of all immediate {@link State}
   *     changes caused by this call.
   */
  @ForOverride
  protected ListenableFuture<?> handleStop() {
    throw new IllegalStateException("Missing implementation to handle COMMAND_STOP");
  }

  /**
   * Handles calls to {@link Player#release}.
   *
   * <p>Will only be called if {@link Player#COMMAND_RELEASE} is available.
   *
   * @return A {@link ListenableFuture} indicating the completion of all immediate {@link State}
   *     changes caused by this call.
   */
  @ForOverride
  protected ListenableFuture<?> handleRelease() {
    throw new IllegalStateException("Missing implementation to handle COMMAND_RELEASE");
  }

  /**
   * Handles calls to {@link Player#setRepeatMode}.
   *
   * <p>Will only be called if {@link Player#COMMAND_SET_REPEAT_MODE} is available.
   *
   * @param repeatMode The requested {@link RepeatMode}.
   * @return A {@link ListenableFuture} indicating the completion of all immediate {@link State}
   *     changes caused by this call.
   */
  @ForOverride
  protected ListenableFuture<?> handleSetRepeatMode(@RepeatMode int repeatMode) {
    throw new IllegalStateException("Missing implementation to handle COMMAND_SET_REPEAT_MODE");
  }

  /**
   * Handles calls to {@link Player#setShuffleModeEnabled}.

View on GitHub (pinned to dd430f7053)

Solutions

  1. Override handleRelease() to tear down your backend and return a future completed when fully released; also set STATE_IDLE per the documented contract.
  2. Alternatively remove COMMAND_RELEASE from availableCommands — but note most clients unconditionally call release(), so implementing it is usually correct.
  3. Make handleRelease idempotent so double-release does not fail.

Example fix

// before
// subclass without handleRelease -> player.release() throws

// after
@Override
protected ListenableFuture<?> handleRelease() {
  backend.shutdown();
  return updateStateAndNotify(
      new State.Builder().setPlaybackState(STATE_IDLE).setPlaylist(Collections.emptyList()).build());
}
Defensive patterns

Strategy: validation

Validate before calling

if (!supportsRelease) commands.remove(Player.COMMAND_RELEASE); // rarely correct — most clients call release()

Prevention

When it happens

Trigger: Calling player.release() on a SimpleBasePlayer subclass that did not override handleRelease() while its State includes COMMAND_RELEASE.

Common situations: Custom player implementations that clean up resources elsewhere (e.g. in a close() method) but forget the handler; test harnesses that always call release().

Related errors


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