{"record":{"id":"8b0c9bc9d9ede112","repo":"google/ExoPlayer","slug":"missing-implementation-to-handle-command-set-volum","errorCode":null,"errorMessage":"Missing implementation to handle COMMAND_SET_VOLUME","messagePattern":"Missing implementation to handle COMMAND_SET_VOLUME","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"library/common/src/main/java/com/google/android/exoplayer2/SimpleBasePlayer.java","lineNumber":3054,"sourceCode":"  @ForOverride\n  protected ListenableFuture<?> handleSetPlaylistMetadata(MediaMetadata playlistMetadata) {\n    throw new IllegalStateException(\n        \"Missing implementation to handle COMMAND_SET_PLAYLIST_METADATA\");\n  }\n\n  /**\n   * Handles calls to {@link Player#setVolume}.\n   *\n   * <p>Will only be called if {@link Player#COMMAND_SET_VOLUME} is available.\n   *\n   * @param volume The requested audio volume, with 0 being silence and 1 being unity gain (signal\n   *     unchanged).\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<?> handleSetVolume(@FloatRange(from = 0, to = 1.0) float volume) {\n    throw new IllegalStateException(\"Missing implementation to handle COMMAND_SET_VOLUME\");\n  }\n\n  /**\n   * Handles calls to {@link Player#setDeviceVolume(int)} and {@link Player#setDeviceVolume(int,\n   * int)}.\n   *\n   * <p>Will only be called if {@link Player#COMMAND_SET_DEVICE_VOLUME} or {@link\n   * Player#COMMAND_SET_DEVICE_VOLUME_WITH_FLAGS} is available.\n   *\n   * @param deviceVolume The requested device volume.\n   * @param flags Either 0 or a bitwise combination of one or more {@link C.VolumeFlags}.\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<?> handleSetDeviceVolume(\n      @IntRange(from = 0) int deviceVolume, int flags) {\n    throw new IllegalStateException(","sourceCodeStart":3036,"sourceCodeEnd":3072,"githubUrl":"https://github.com/google/ExoPlayer/blob/dd430f7053a1a3958deea3ead6a0565150c06bfc/library/common/src/main/java/com/google/android/exoplayer2/SimpleBasePlayer.java#L3036-L3072","documentation":"SimpleBasePlayer is an abstract base class that delegates every Player call to a protected handle* method. If a subclass advertises Player.COMMAND_SET_VOLUME in getState().availableCommands but does not override handleSetVolume(float), the default implementation throws this IllegalStateException as soon as Player.setVolume is called. The error therefore signals a contract violation between the declared available commands and the implemented handlers.","triggerScenarios":"Calling player.setVolume(...) on a custom SimpleBasePlayer subclass whose State built with State.Builder.setAvailableCommands(...) includes Player.COMMAND_SET_VOLUME, while handleSetVolume was never overridden.","commonSituations":"Building a custom player on top of SimpleBasePlayer and copying a large availableCommands set (e.g. from Player.Commands.DEFAULT or another player) without implementing every corresponding handler; adding volume support to availableCommands before writing the handler.","solutions":["Override protected ListenableFuture<?> handleSetVolume(float volume) in your SimpleBasePlayer subclass and apply the volume, returning immediateFuture(null) or a future for async work.","If volume control is not supported, remove Player.COMMAND_SET_VOLUME from the availableCommands in the State returned by getState(), so Player.setVolume becomes a no-op instead of throwing.","Audit all handle* methods against every command you declare in availableCommands; each advertised command must have a matching override."],"exampleFix":"// before\nsetState(new State.Builder().setAvailableCommands(new Player.Commands.Builder().add(Player.COMMAND_SET_VOLUME).build())...build());\n// handleSetVolume not overridden -> IllegalStateException on setVolume()\n\n// after\n@Override\nprotected ListenableFuture<?> handleSetVolume(float volume) {\n  state = state.buildUpon().setVolume(volume).build();\n  return Futures.immediateVoidFuture();\n}","handlingStrategy":"validation","validationCode":"// Before exposing the player, assert every advertised command has a handler.\nPlayer.Commands cmds = player.getState().availableCommands;\nif (cmds.contains(Player.COMMAND_SET_VOLUME)\n    && !overridesHandler(playerClass, \"handleSetVolume\")) {\n  throw new IllegalStateException(\"COMMAND_SET_VOLUME advertised but handleSetVolume missing\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Start from the smallest availableCommands set and add commands only as you implement each handle* method.","Write a reflection-based test that maps every COMMAND_* constant to its handle* method and asserts an override exists when the command is advertised.","Do not copy Player.Commands.DEFAULT blindly; it includes commands whose handlers you may not have written."],"tags":["exoplayer","media3","player","volume","subclassing"],"backgroundTag":null,"analyzedSha":"dd430f7053a1a3958deea3ead6a0565150c06bfc","analyzedAt":"2026-08-14T12:22:02.982Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}