{"record":{"id":"7b885d3377dc7689","repo":"redis/jedis","slug":"commandobjects-must-not-be-null-or-empty","errorCode":null,"errorMessage":"commandObjects must not be null or empty","messagePattern":"commandObjects must not be null or empty","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"src/main/java/redis/clients/jedis/executors/ClusterCommandExecutor.java","lineNumber":159,"sourceCode":"   * This method is designed for commands that need to operate on keys distributed across multiple\n   * hash slots (e.g., DEL, EXISTS, MGET with keys from different slots). Each CommandObject in the\n   * list is executed on its appropriate shard based on the key's hash slot, and the results are\n   * aggregated using the command's response policy.\n   * <p>\n   * Error handling depends on the command's response policy:\n   * <ul>\n   *   <li>{@code ONE_SUCCEEDED}: Returns success if at least one shard succeeds</li>\n   *   <li>Other policies: Throws {@link JedisBroadcastException} if any shard fails</li>\n   * </ul>\n   *\n   * @param commandObjects list of CommandObject instances, each targeting keys in the same hash slot\n   * @param <T> the return type of the command\n   * @return the aggregated reply from all shards\n   * @throws JedisBroadcastException if error handling criteria based on response policy are not met\n   */\n  public final <T> T executeMultiShardCommand(List<CommandObject<T>> commandObjects) {\n    if (commandObjects == null || commandObjects.isEmpty()) {\n      throw new IllegalArgumentException(\"commandObjects must not be null or empty\");\n    }\n\n    // Get the response policy from the first command (all commands should have the same policy)\n    CommandFlagsRegistry.ResponsePolicy responsePolicy = flags.getResponsePolicy(\n        commandObjects.get(0).getArguments());\n\n    MultiNodeResultAggregator<T> aggregator = new MultiNodeResultAggregator<>(responsePolicy);\n\n    for (CommandObject<T> commandObject : commandObjects) {\n      try {\n        // Execute each command on its appropriate shard using the existing retry logic\n        T aReply = doExecuteCommand(commandObject, slotBasedConnectionResolver, true);\n        aggregator.addSuccess(aReply);\n      } catch (Exception anError) {\n        // Extract node from exception (JedisClusterOperationException includes node info)\n        aggregator.addError(anError);\n      }\n    }","sourceCodeStart":141,"sourceCodeEnd":177,"githubUrl":"https://github.com/redis/jedis/blob/6dac31d4c224fb3257c216f3985340c6f500cdcb/src/main/java/redis/clients/jedis/executors/ClusterCommandExecutor.java#L141-L177","documentation":"ClusterCommandExecutor.executeMultiShardCommand broadcasts a command to all shards and aggregates the replies according to the command's response policy. It throws IllegalArgumentException when the list of CommandObjects is null or empty, because there is nothing to route or a policy to derive. This is an input-validation guard at the entry of the broadcast API.","triggerScenarios":"Calling `clusterClient executeMultiShardCommand(List)` with a null list, or with an empty list produced by filtering an empty key/command set (e.g. no commands matched a pattern before broadcasting).","commonSituations":"Cluster-wide commands (FLUSHDB, DBSIZE, CONFIG GET, keyspace scanning) built programmatically where the command list construction returned empty; calling broadcast APIs on a cluster client that hasn't had any commands registered.","solutions":["Ensure the list passed to executeMultiShardCommand contains at least one CommandObject before calling.","If the list is built by filtering, check `list.isEmpty()` first and either skip the broadcast or return a sensible empty result instead.","Fix the code that produces null lists (initialize collections to empty rather than null)."],"exampleFix":"// before\nreturn executor.executeMultiShardCommand(commands);\n// after\nif (commands == null || commands.isEmpty()) {\n  throw new IllegalArgumentException(\"at least one command is required\");\n}\nreturn executor.executeMultiShardCommand(commands);","handlingStrategy":"validation","validationCode":"if (commandObjects == null || commandObjects.isEmpty()) {\n  // skip broadcast or return an empty aggregated result\n  return null;\n}","typeGuard":null,"tryCatchPattern":"try {\n  return executor.executeMultiShardCommand(commands);\n} catch (IllegalArgumentException e) {\n  logger.warn(\"broadcast skipped: no commands\", e);\n  return null;\n}","preventionTips":["Initialize command collections as empty lists, never null","Check list size before cluster-wide broadcast calls","Centralize broadcast calls in a helper that guards the empty case"],"tags":["cluster","broadcast","argument-validation","empty-collection"],"backgroundTag":"missing-required-argument","analyzedSha":"6dac31d4c224fb3257c216f3985340c6f500cdcb","analyzedAt":"2026-09-08T04:55:01.204Z","contentChangedAt":"2026-09-08T04:55:01.204Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}