{"record":{"id":"ee7cac55ab7affbe","repo":"redisson/redisson","slug":"clustered-rename-is-not-supported-in-a-pipeline-ee7cac","errorCode":null,"errorMessage":"Clustered rename is not supported in a pipeline","messagePattern":"Clustered rename is not supported in a pipeline","errorType":"exception","errorClass":"InvalidDataAccessResourceUsageException","httpStatus":null,"severity":"error","filePath":"redisson-spring/redisson-spring-data/redisson-spring-data-24/src/main/java/org/redisson/spring/data/connection/RedissonClusterConnection.java","lineNumber":433,"sourceCode":"                \n                RFuture<ListScanResult<byte[]>> f = executorService.readAsync(client, ByteArrayCodec.INSTANCE, RedisCommands.SCAN, args.toArray());\n                ListScanResult<byte[]> res = syncFuture(f);\n                String pos = res.getPos();\n                client = res.getRedisClient();\n                if (\"0\".equals(pos)) {\n                    client = null;\n                }\n                \n                return new ScanIteration<byte[]>(Long.parseUnsignedLong(pos), res.getValues());\n            }\n        }.open();\n    }\n\n    @Override\n    public void rename(byte[] oldName, byte[] newName) {\n\n        if (isPipelined()) {\n            throw new InvalidDataAccessResourceUsageException(\"Clustered rename is not supported in a pipeline\");\n        }\n\n        if (executorService.getConnectionManager().calcSlot(oldName) == executorService.getConnectionManager().calcSlot(newName)) {\n            super.rename(oldName, newName);\n            return;\n        }\n\n        final byte[] value = dump(oldName);\n\n        if (null != value) {\n\n            final Long sourceTtlInSeconds = ttl(oldName);\n\n            final long ttlInMilliseconds;\n            if (null != sourceTtlInSeconds && sourceTtlInSeconds > 0) {\n                ttlInMilliseconds = sourceTtlInSeconds * 1000;\n            } else {\n                ttlInMilliseconds = 0;","sourceCodeStart":415,"sourceCodeEnd":451,"githubUrl":"https://github.com/redisson/redisson/blob/91188987c2a9023e7fedabff758681ad9b107f25/redisson-spring/redisson-spring-data/redisson-spring-data-24/src/main/java/org/redisson/spring/data/connection/RedissonClusterConnection.java#L415-L451","documentation":"In cluster mode, RENAME works only when source and destination hash to the same slot. Redisson implements cross-slot rename manually (DUMP the value, read TTL, RESTORE at the new key, DEL the old) — a multi-step, non-atomic sequence that cannot be buffered in a pipeline. Therefore rename() inside an open pipeline throws InvalidDataAccessResourceUsageException.","triggerScenarios":"Calling connection.rename(oldName, newName) while isPipelined() is true (after openPipeline()). Same-slot renames would delegate to super.rename(), but the pipeline check runs first, so ANY rename in a pipeline throws, regardless of slot.","commonSituations":"Generic Spring Redis DAOs that wrap all mutations in executePipelined(); code ported from a non-cluster or Lettuce setup where pipelined rename worked; batch rename loops that were 'optimized' with pipelining when moving to cluster.","solutions":["Exclude rename/renameNX from pipelined blocks: close the pipeline, perform the rename, then continue batching","If source and destination are known same-slot (e.g. hash tags like {user:1}:a -> {user:1}:b), call the underlying single-command rename outside the pipeline — it is then a single RENAME","Design keys with matching hash tags so renames stay single-slot and atomic"],"exampleFix":"// before\nconnection.openPipeline();\nconnection.rename(oldKey, newKey); // throws\nconnection.closePipeline();\n\n// after\nconnection.closePipeline();\nconnection.rename(oldKey, newKey);\nconnection.openPipeline(); // resume batching other commands","handlingStrategy":"validation","validationCode":"// Guard before pipelining anything that may rename:\nif (connection.isPipelined()) {\n    connection.closePipeline(); // or use a separate connection for the rename\n}\nconnection.rename(oldKey, newKey);","typeGuard":null,"tryCatchPattern":"try {\n    connection.rename(oldKey, newName);\n} catch (InvalidDataAccessResourceUsageException e) {\n    // rename inside pipeline: close pipeline, retry outside, reopen if needed\n    connection.closePipeline();\n    connection.rename(oldKey, newName);\n}","preventionTips":["Exclude rename/renameNX from pipelined batches by design","Use hash tags ({tag}:key) so related keys share a slot and rename stays atomic","Audit generic DAO 'executePipelined everything' advice when moving to cluster mode"],"tags":["redis","redisson","cluster","rename","pipeline","cross-slot"],"backgroundTag":null,"analyzedSha":"91188987c2a9023e7fedabff758681ad9b107f25","analyzedAt":"2026-08-14T11:39:42.619Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}