redis/jedis · error · IllegalArgumentException

TS.NRANGE/TS.NREVRANGE require at least one key

Error message

TS.NRANGE/TS.NREVRANGE require at least one key

What it means

checkNRangeKeys() guards the TimeSeries TS.NRANGE/TS.NREVRANGE command objects: these multi-key commands require at least one key. An empty or null key array cannot form a valid server command, so IllegalArgumentException is thrown client-side.

Solutions

  1. Check keys != null && keys.length > 0 before invoking tsNRange/tsNRevRange
  2. Guard the upstream key-collection logic so at least one key is always present
  3. If keys may legitimately be empty, skip the call instead of issuing the command

Example fix

// before
ts.tsNRange(from, to, keys); // keys may be empty
// after
if (keys != null && keys.length > 0) {
  ts.tsNRange(from, to, keys);
}
Defensive patterns

Strategy: validation

Validate before calling

if (keys == null || keys.length == 0) { throw new IllegalStateException("tsNRange requires at least one key"); }

Type guard

static boolean hasKeys(String[] k) { return k != null && k.length > 0; }

Try / catch

try { ts.tsNRange(from, to, keys); } catch (IllegalArgumentException e) { log.warn("skipping NRANGE: no keys"); }

Prevention

When it happens

Trigger: Calling the tsNRange/tsNRevRange CommandObjects methods with a null String[] or a zero-length array, e.g. tsNRange(from, to, new String[0]) or spreading an empty collection.

Common situations: Passing a dynamically built key list that ended up empty (no keys matched a filter upstream); calling the varargs method with no keys; forgetting that varargs spread of an empty list yields an empty array.

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/ac7b8971f22f22a3. Report an issue: GitHub.

Appendix: source

Thrown at src/main/java/redis/clients/jedis/CommandObjects.java:4868

  public final CommandObject<List<TSElement>> tsNRevRange(String[] keys, long fromTimestamp, long toTimestamp) {
    checkNRangeKeys(keys);
    return new CommandObject<>(commandArguments(TimeSeriesCommand.NREVRANGE).add(keys.length)
        .keys((Object[]) keys).add(fromTimestamp).add(toTimestamp),
        TimeSeriesBuilderFactory.TIMESERIES_PIVOT_ELEMENT_LIST);
  }

  public final CommandObject<List<TSElement>> tsNRevRange(String[] keys, TSNRangeParams nrangeParams) {
    checkNRangeKeys(keys);
    nrangeParams.validateAggregationForKeys(keys.length);
    return new CommandObject<>(commandArguments(TimeSeriesCommand.NREVRANGE).add(keys.length)
        .keys((Object[]) keys).addParams(nrangeParams),
        TimeSeriesBuilderFactory.TIMESERIES_PIVOT_ELEMENT_LIST);
  }

  private static void checkNRangeKeys(String[] keys) {
    if (keys == null || keys.length == 0) {
      throw new IllegalArgumentException("TS.NRANGE/TS.NREVRANGE require at least one key");
    }
  }

  public final CommandObject<Map<String, TSMRangeElements>> tsMRange(long fromTimestamp, long toTimestamp, String... filters) {
    return new CommandObject<>(commandArguments(TimeSeriesCommand.MRANGE).add(fromTimestamp)
        .add(toTimestamp).add(TimeSeriesKeyword.FILTER).addObjects((Object[]) filters),
        getTimeseriesMultiRangeResponseBuilder());
  }

  public final CommandObject<Map<String, TSMRangeElements>> tsMRange(TSMRangeParams multiRangeParams) {
    return new CommandObject<>(commandArguments(TimeSeriesCommand.MRANGE)
        .addParams(multiRangeParams), getTimeseriesMultiRangeResponseBuilder());
  }

  public final CommandObject<Map<String, TSMRangeElements>> tsMRevRange(long fromTimestamp, long toTimestamp, String... filters) {
    return new CommandObject<>(commandArguments(TimeSeriesCommand.MREVRANGE).add(fromTimestamp)
        .add(toTimestamp).add(TimeSeriesKeyword.FILTER).addObjects((Object[]) filters),
        getTimeseriesMultiRangeResponseBuilder());

View on GitHub (pinned to 6dac31d4c2)