redis/jedis · error · IllegalArgumentException

commandObjects must not be null or empty

Error message

commandObjects must not be null or empty

What it means

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.

Solutions

  1. Ensure the list passed to executeMultiShardCommand contains at least one CommandObject before calling.
  2. If the list is built by filtering, check `list.isEmpty()` first and either skip the broadcast or return a sensible empty result instead.
  3. Fix the code that produces null lists (initialize collections to empty rather than null).

Example fix

// before
return executor.executeMultiShardCommand(commands);
// after
if (commands == null || commands.isEmpty()) {
  throw new IllegalArgumentException("at least one command is required");
}
return executor.executeMultiShardCommand(commands);
Defensive patterns

Strategy: validation

Validate before calling

if (commandObjects == null || commandObjects.isEmpty()) {
  // skip broadcast or return an empty aggregated result
  return null;
}

Try / catch

try {
  return executor.executeMultiShardCommand(commands);
} catch (IllegalArgumentException e) {
  logger.warn("broadcast skipped: no commands", e);
  return null;
}

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of redis/jedis@6dac31d4c2 (2026-09-08). Data as JSON: /api/errors/7b885d3377dc7689. Report an issue: GitHub.

Appendix: source

Thrown at src/main/java/redis/clients/jedis/executors/ClusterCommandExecutor.java:159

   * This method is designed for commands that need to operate on keys distributed across multiple
   * hash slots (e.g., DEL, EXISTS, MGET with keys from different slots). Each CommandObject in the
   * list is executed on its appropriate shard based on the key's hash slot, and the results are
   * aggregated using the command's response policy.
   * <p>
   * Error handling depends on the command's response policy:
   * <ul>
   *   <li>{@code ONE_SUCCEEDED}: Returns success if at least one shard succeeds</li>
   *   <li>Other policies: Throws {@link JedisBroadcastException} if any shard fails</li>
   * </ul>
   *
   * @param commandObjects list of CommandObject instances, each targeting keys in the same hash slot
   * @param <T> the return type of the command
   * @return the aggregated reply from all shards
   * @throws JedisBroadcastException if error handling criteria based on response policy are not met
   */
  public final <T> T executeMultiShardCommand(List<CommandObject<T>> commandObjects) {
    if (commandObjects == null || commandObjects.isEmpty()) {
      throw new IllegalArgumentException("commandObjects must not be null or empty");
    }

    // Get the response policy from the first command (all commands should have the same policy)
    CommandFlagsRegistry.ResponsePolicy responsePolicy = flags.getResponsePolicy(
        commandObjects.get(0).getArguments());

    MultiNodeResultAggregator<T> aggregator = new MultiNodeResultAggregator<>(responsePolicy);

    for (CommandObject<T> commandObject : commandObjects) {
      try {
        // Execute each command on its appropriate shard using the existing retry logic
        T aReply = doExecuteCommand(commandObject, slotBasedConnectionResolver, true);
        aggregator.addSuccess(aReply);
      } catch (Exception anError) {
        // Extract node from exception (JedisClusterOperationException includes node info)
        aggregator.addError(anError);
      }
    }

View on GitHub (pinned to 6dac31d4c2)