{"record":{"id":"fecfab2c6474ec7a","repo":"google/ExoPlayer","slug":"missing-implementation-to-handle-command-play-paus","errorCode":null,"errorMessage":"Missing implementation to handle COMMAND_PLAY_PAUSE","messagePattern":"Missing implementation to handle COMMAND_PLAY_PAUSE","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"library/common/src/main/java/com/google/android/exoplayer2/SimpleBasePlayer.java","lineNumber":2927,"sourceCode":"    return new MediaItemData.Builder(new PlaceholderUid())\n        .setMediaItem(mediaItem)\n        .setIsDynamic(true)\n        .setIsPlaceholder(true)\n        .build();\n  }\n\n  /**\n   * Handles calls to {@link Player#setPlayWhenReady}, {@link Player#play} and {@link Player#pause}.\n   *\n   * <p>Will only be called if {@link Player#COMMAND_PLAY_PAUSE} is available.\n   *\n   * @param playWhenReady The requested {@link State#playWhenReady}\n   * @return A {@link ListenableFuture} indicating the completion of all immediate {@link State}\n   *     changes caused by this call.\n   */\n  @ForOverride\n  protected ListenableFuture<?> handleSetPlayWhenReady(boolean playWhenReady) {\n    throw new IllegalStateException(\"Missing implementation to handle COMMAND_PLAY_PAUSE\");\n  }\n\n  /**\n   * Handles calls to {@link Player#prepare}.\n   *\n   * <p>Will only be called if {@link Player#COMMAND_PREPARE} is available.\n   *\n   * @return A {@link ListenableFuture} indicating the completion of all immediate {@link State}\n   *     changes caused by this call.\n   */\n  @ForOverride\n  protected ListenableFuture<?> handlePrepare() {\n    throw new IllegalStateException(\"Missing implementation to handle COMMAND_PREPARE\");\n  }\n\n  /**\n   * Handles calls to {@link Player#stop}.\n   *","sourceCodeStart":2909,"sourceCodeEnd":2945,"githubUrl":"https://github.com/google/ExoPlayer/blob/dd430f7053a1a3958deea3ead6a0565150c06bfc/library/common/src/main/java/com/google/android/exoplayer2/SimpleBasePlayer.java#L2909-L2945","documentation":"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.","triggerScenarios":"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).","commonSituations":"Writing a custom SimpleBasePlayer and forgetting one handler; copying available-command sets from an example; adding a command to availableCommands without implementing its handler.","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."],"exampleFix":"// before\npublic class MyPlayer extends SimpleBasePlayer {\n  // no handleSetPlayWhenReady -> play() throws\n}\n\n// after\n@Override\nprotected ListenableFuture<?> handleSetPlayWhenReady(boolean playWhenReady) {\n  return updateStateAndNotify(\n      state.buildUpon().setPlayWhenReady(playWhenReady).build());\n}","handlingStrategy":"validation","validationCode":"// Before exposing the player, ensure handler exists or command absent:\nState state = new State.Builder()\n    .setAvailableCommands(buildAvailableCommands()) // omit COMMAND_PLAY_PAUSE if unimplemented\n    .build();","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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."],"tags":["simplebaseplayer","custom-player","playback-control","media3","contract"],"backgroundTag":null,"analyzedSha":"dd430f7053a1a3958deea3ead6a0565150c06bfc","analyzedAt":"2026-08-14T12:22:02.982Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}