redisson/redisson · error · InvalidDataAccessApiUsageException

%s PUSHX only allows one value!

Error message

%s PUSHX only allows one value!

What it means

RedissonReactiveListCommands.push(PushCommand) throws InvalidDataAccessApiUsageException('<dir> PUSHX only allows one value!') when the command has upsert=false (meaning LPUSHX/RPUSHX semantics) but carries more than one value. Redis' PUSHX commands accept exactly one value, unlike plain LPUSH/RPUSH.

Source

Thrown at redisson-spring/redisson-spring-data/redisson-spring-data-20/src/main/java/org/redisson/spring/data/connection/RedissonReactiveListCommands.java:68

    private static final RedisStrictCommand<Long> RPUSH = new RedisStrictCommand<Long>("RPUSH");
    private static final RedisStrictCommand<Long> LPUSH = new RedisStrictCommand<Long>("LPUSH");
    private static final RedisStrictCommand<Long> RPUSHX = new RedisStrictCommand<Long>("RPUSHX");
    private static final RedisStrictCommand<Long> LPUSHX = new RedisStrictCommand<Long>("LPUSHX");

    RedissonReactiveListCommands(CommandReactiveExecutor executorService) {
        super(executorService);
    }

    @Override
    public Flux<NumericResponse<PushCommand, Long>> push(Publisher<PushCommand> commands) {
        return execute(commands, command -> {

            Assert.notNull(command.getKey(), "Key must not be null!");
            Assert.notEmpty(command.getValues(), "Values must not be null or empty!");

            if (!command.getUpsert() && command.getValues().size() > 1) {
                throw new InvalidDataAccessApiUsageException(
                        String.format("%s PUSHX only allows one value!", command.getDirection()));
            }

            RedisStrictCommand<Long> redisCommand;
            
            List<Object> params = new ArrayList<Object>();
            params.add(toByteArray(command.getKey()));
            params.addAll(command.getValues().stream().map(v -> toByteArray(v)).collect(Collectors.toList()));

            if (ObjectUtils.nullSafeEquals(Direction.RIGHT, command.getDirection())) {
                if (command.getUpsert()) {
                    redisCommand = RPUSH;
                } else {
                    redisCommand = RPUSHX;
                }
            } else {
                if (command.getUpsert()) {
                    redisCommand = LPUSH;

View on GitHub (pinned to 91188987c2)

Solutions

  1. Split multiple values into one PushX command per value, each with a single-element values list.
  2. If the key is guaranteed to exist, drop untilAbsent()/upsert(false) so plain LPUSH/RPUSH handles multiple values.
  3. Validate values.size() <= 1 before submitting an upsert=false command.

Example fix

// before
PushCommand cmd = PushCommand.push(key, Direction.RIGHT, v1, v2).untilAbsent(true);
listCommands.push(Flux.just(cmd)); // throws: RIGHT PUSHX only allows one value!

// after
Flux<PushCommand> cmds = Flux.just(
    PushCommand.push(key, Direction.RIGHT, v1).untilAbsent(true),
    PushCommand.push(key, Direction.RIGHT, v2).untilAbsent(true));
listCommands.push(cmds);
Defensive patterns

Strategy: validation

Validate before calling

// split multi-value upsert=false pushes into single-value commands
List<PushCommand> safe = new ArrayList<>();
if (!cmd.getUpsert() && cmd.getValues().size() > 1) {
    for (ByteBuffer v : cmd.getValues()) {
        safe.add(PushCommand.push(cmd.getKey(), cmd.getDirection(), v).untilAbsent(true));
    }
} else {
    safe.add(cmd);
}

Type guard

boolean isValidPushX(PushCommand cmd) {
    return cmd.getUpsert() || cmd.getValues().size() <= 1;
}

Prevention

When it happens

Trigger: Building a PushCommand via RedisListCommands.PushCommand.push(key, value, direction).untilAbsent(true) — or setting upsert(false) — with a values list of length > 1, then executing it through the reactive list commands.

Common situations: Reusing a generic 'push many values' helper for both upsert and non-upsert paths; switching a working multi-value LPUSH to untilAbsent() without splitting values.

Related errors


AI-assisted analysis of redisson/redisson@91188987c2 (2026-08-14). Data as JSON: /api/errors/7ea566bd8d6eccc1. Report an issue: GitHub.