google/ExoPlayer · error · IllegalStateException
Missing implementation to handle COMMAND_PLAY_PAUSE
Error message
Missing implementation to handle COMMAND_PLAY_PAUSE
What it means
SimpleBasePlayer is an abstract base that routes Player commands to protected handle* methods; the default implementations throw IllegalStateException. This one fires when the player state advertises COMMAND_PLAY_PAUSE as available but the subclass did not override handleSetPlayWhenReady(boolean). It is a contract violation inside a custom player implementation, not a runtime media error.
Source
Thrown at library/common/src/main/java/com/google/android/exoplayer2/SimpleBasePlayer.java:2927
return new MediaItemData.Builder(new PlaceholderUid())
.setMediaItem(mediaItem)
.setIsDynamic(true)
.setIsPlaceholder(true)
.build();
}
/**
* Handles calls to {@link Player#setPlayWhenReady}, {@link Player#play} and {@link Player#pause}.
*
* <p>Will only be called if {@link Player#COMMAND_PLAY_PAUSE} is available.
*
* @param playWhenReady The requested {@link State#playWhenReady}
* @return A {@link ListenableFuture} indicating the completion of all immediate {@link State}
* changes caused by this call.
*/
@ForOverride
protected ListenableFuture<?> handleSetPlayWhenReady(boolean playWhenReady) {
throw new IllegalStateException("Missing implementation to handle COMMAND_PLAY_PAUSE");
}
/**
* Handles calls to {@link Player#prepare}.
*
* <p>Will only be called if {@link Player#COMMAND_PREPARE} is available.
*
* @return A {@link ListenableFuture} indicating the completion of all immediate {@link State}
* changes caused by this call.
*/
@ForOverride
protected ListenableFuture<?> handlePrepare() {
throw new IllegalStateException("Missing implementation to handle COMMAND_PREPARE");
}
/**
* Handles calls to {@link Player#stop}.
*View on GitHub (pinned to dd430f7053)
Solutions
- Override protected ListenableFuture<?> handleSetPlayWhenReady(boolean playWhenReady) in your subclass and return an immediate future (Futures.immediateFuture(null)) after updating state.
- If play/pause is not supported, remove COMMAND_PLAY_PAUSE from the commands in your State.
- Unit-test every advertised command by calling it against a State built with default commands.
Example fix
// before
public class MyPlayer extends SimpleBasePlayer {
// no handleSetPlayWhenReady -> play() throws
}
// after
@Override
protected ListenableFuture<?> handleSetPlayWhenReady(boolean playWhenReady) {
return updateStateAndNotify(
state.buildUpon().setPlayWhenReady(playWhenReady).build());
} Defensive patterns
Strategy: validation
Validate before calling
// Before exposing the player, ensure handler exists or command absent:
State state = new State.Builder()
.setAvailableCommands(buildAvailableCommands()) // omit COMMAND_PLAY_PAUSE if unimplemented
.build(); Prevention
- For every command in your State's availableCommands, implement the matching handle* method.
- Write a reflection-based unit test asserting each advertised command has an overridden handler.
- Return Futures.immediateVoidFuture() from trivial handlers after updateStateAndNotify.
When it happens
Trigger: A SimpleBasePlayer subclass's State.Builder sets COMMAND_PLAY_PAUSE available (or never overrides isCommandAvailable to exclude it) and the app calls play(), pause(), or setPlayWhenReady(true/false).
Common situations: Writing a custom SimpleBasePlayer and forgetting one handler; copying available-command sets from an example; adding a command to availableCommands without implementing its handler.
Related errors
- Missing implementation to handle COMMAND_PREPARE
- Missing implementation to handle COMMAND_STOP
- Missing implementation to handle COMMAND_RELEASE
- Missing implementation to handle COMMAND_SET_REPEAT_MODE
- Missing implementation to handle COMMAND_SET_SHUFFLE_MODE
AI-assisted analysis of google/ExoPlayer@dd430f7053 (2026-08-14).
Data as JSON: /api/errors/fecfab2c6474ec7a.
Report an issue: GitHub.