{"record":{"id":"e10611238aec1075","repo":"redisson/redisson","slug":"command-must-not-define-expiration-nor-option-for","errorCode":null,"errorMessage":"Command must not define expiration nor option for GETSET.","messagePattern":"Command must not define expiration nor option for GETSET\\.","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"redisson-spring/redisson-spring-data/redisson-spring-data-20/src/main/java/org/redisson/spring/data/connection/RedissonReactiveStringCommands.java","lineNumber":122,"sourceCode":"\n            Assert.notNull(command.getKey(), \"Key must not be null!\");\n\n            byte[] keyBuf = toByteArray(command.getKey());\n            Mono<byte[]> m = read(keyBuf, ByteArrayCodec.INSTANCE, RedisCommands.GET, keyBuf);\n            return m.map(v -> new ByteBufferResponse<>(command, ByteBuffer.wrap(v)))\n                    .defaultIfEmpty(new AbsentByteBufferResponse<>(command));\n        });\n    }\n\n    @Override\n    public Flux<ByteBufferResponse<SetCommand>> getSet(Publisher<SetCommand> commands) {\n        return execute(commands, command -> {\n\n            Assert.notNull(command.getKey(), \"Key must not be null!\");\n            Assert.notNull(command.getValue(), \"Value must not be null!\");\n\n            if (command.getExpiration().isPresent() || command.getOption().isPresent()) {\n                throw new IllegalArgumentException(\"Command must not define expiration nor option for GETSET.\");\n            }\n\n            byte[] keyBuf = toByteArray(command.getKey());\n            byte[] valueBuf = toByteArray(command.getValue());\n            \n            Mono<byte[]> m = write(keyBuf, ByteArrayCodec.INSTANCE, RedisCommands.GETSET, keyBuf, valueBuf);\n            return m.map(v -> new ByteBufferResponse<>(command, ByteBuffer.wrap(v)));\n        });\n    }\n\n    @Override\n    public Flux<MultiValueResponse<List<ByteBuffer>, ByteBuffer>> mGet(Publisher<List<ByteBuffer>> keysets) {\n        return execute(keysets, coll -> {\n\n            Assert.notNull(coll, \"List must not be null!\");\n            \n            Object[] params = coll.stream().map(buf -> toByteArray(buf)).toArray(Object[]::new);\n","sourceCodeStart":104,"sourceCodeEnd":140,"githubUrl":"https://github.com/redisson/redisson/blob/91188987c2a9023e7fedabff758681ad9b107f25/redisson-spring/redisson-spring-data/redisson-spring-data-20/src/main/java/org/redisson/spring/data/connection/RedissonReactiveStringCommands.java#L104-L140","documentation":"RedissonReactiveStringCommands.getSet(Publisher<SetCommand>) throws IllegalArgumentException('Command must not define expiration nor option for GETSET.') when a SetCommand passed to GETSET carries an expiration or a set option. GETSET is semantically a plain atomic replace-and-return-old-value command and maps to no SET EX/PX/NX/XX variant, so those fields must be empty.","triggerScenarios":"Building a SetCommand with SetOption.expiration(Expiration) or SetOption.ifExists()/ifAbsent() (or command.set(…)) and then submitting it to getSet(...) instead of set(...).","commonSituations":"Copy-pasting SetCommand construction from a set() call site into getSet(); generic 'write value with TTL' helpers routed to the wrong command method.","solutions":["Use SetCommand.set(key, value) with no expiration and no option when calling getSet.","If TTL/conditional semantics are needed, use set(...) and a separate get(...), or the SET command's own options via set().","Add a debug assertion that getExpiration() and getOption() are empty before invoking getSet."],"exampleFix":"// before\nSetCommand cmd = SetCommand.set(key, value, Expiration.from(60, TimeUnit.SECONDS));\nstringCommands.getSet(Flux.just(cmd)); // throws\n\n// after\nSetCommand cmd = SetCommand.set(key, value);\nstringCommands.getSet(Flux.just(cmd));","handlingStrategy":"validation","validationCode":"if (cmd.getExpiration().isPresent() || cmd.getOption().isPresent()) {\n    throw new IllegalArgumentException(\"GETSET requires a bare SetCommand\");\n}\nstringCommands.getSet(Flux.just(cmd));","typeGuard":"boolean isBareSetCommand(SetCommand cmd) {\n    return !cmd.getExpiration().isPresent() && !cmd.getOption().isPresent();\n}","tryCatchPattern":null,"preventionTips":["Use SetCommand.set(key, value) only for getSet; use set(...) for TTL/conditional writes","Type-safe factory methods per Redis command prevent carrying wrong fields"],"tags":["redis","redisson","reactive","string-commands","validation"],"backgroundTag":null,"analyzedSha":"91188987c2a9023e7fedabff758681ad9b107f25","analyzedAt":"2026-08-14T11:39:42.619Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}