{"id":"31c9cc5e63e79836","repo":"redis/redis-py","slug":"unlinking-multiple-keys-is-not-implemented-in-pipe-31c9cc","errorCode":null,"errorMessage":"unlinking multiple keys is not implemented in pipeline command","messagePattern":"unlinking multiple keys is not implemented in pipeline command","errorType":"exception","errorClass":"RedisClusterException","httpStatus":null,"severity":"error","filePath":"redis/cluster.py","lineNumber":4554,"sourceCode":"            \"method watch() is not supported outside of transactional context\"\n        )\n\n    def unwatch(self, *names):\n        raise RedisClusterException(\n            \"method unwatch() is not supported outside of transactional context\"\n        )\n\n    def delete(self, *names):\n        if len(names) != 1:\n            raise RedisClusterException(\n                \"deleting multiple keys is not implemented in pipeline command\"\n            )\n\n        return self.execute_command(\"DEL\", names[0])\n\n    def unlink(self, *names):\n        if len(names) != 1:\n            raise RedisClusterException(\n                \"unlinking multiple keys is not implemented in pipeline command\"\n            )\n\n        return self.execute_command(\"UNLINK\", names[0])\n\n\nclass TransactionStrategy(AbstractStrategy):\n    NO_SLOTS_COMMANDS = {\"UNWATCH\"}\n    IMMEDIATE_EXECUTE_COMMANDS = {\"WATCH\", \"UNWATCH\"}\n    UNWATCH_COMMANDS = {\"DISCARD\", \"EXEC\", \"UNWATCH\"}\n    SLOT_REDIRECT_ERRORS = (AskError, MovedError)\n    CONNECTION_ERRORS = (\n        ConnectionError,\n        OSError,\n        ClusterDownError,\n        SlotNotCoveredError,\n    )\n","sourceCodeStart":4536,"sourceCodeEnd":4572,"githubUrl":"https://github.com/redis/redis-py/blob/da03cdc7e8731092b13e395605c3c1fb2de25de1/redis/cluster.py#L4536-L4572","documentation":"PipelineStrategy.unlink() (redis/cluster.py:4552) raises when len(names) != 1. UNLINK is the non-blocking DEL; the cluster pipeline restricts it to a single key per call for the same slot-routing reason as DEL. Queue one UNLINK per key.","triggerScenarios":"Calling pipe.unlink('k1','k2') (count != 1) on a cluster pipeline.","commonSituations":"Bulk-cleanup code that uses UNLINK for large keys, ported from standalone redis-py. Background jobs that unlink many keys in one pipeline call.","solutions":["Queue one UNLINK per key: for k in keys: pipe.unlink(k).","Group keys under a shared hash tag if you want them on one slot, but still call unlink once per key in the pipeline.","Outside a pipeline, loop rc.unlink(k) per key (or per same-slot batch)."],"exampleFix":"# before\npipe = rc.pipeline()\npipe.unlink('k1', 'k2')  # raises: unlinking multiple keys\npipe.execute()\n\n# after\npipe = rc.pipeline()\nfor k in ['k1', 'k2']:\n    pipe.unlink(k)\npipe.execute()","handlingStrategy":"validation","validationCode":"def pipeline_unlink(pipe, keys):\n    for k in keys:\n        pipe.unlink(k)\n    return pipe","typeGuard":null,"tryCatchPattern":"from redis.exceptions import RedisClusterException\n\ntry:\n    pipe.unlink(*keys)\nexcept RedisClusterException as e:\n    if 'multiple keys' in str(e):\n        for k in keys:\n            pipe.unlink(k)\n    else:\n        raise","preventionTips":["Queue one UNLINK per key in a cluster pipeline.","Use a helper that iterates keys instead of passing them all at once.","Apply the same constraint to DEL and UNLINK in cluster pipeline code."],"tags":["cluster","pipeline","keys","unlink"],"analyzedSha":"da03cdc7e8731092b13e395605c3c1fb2de25de1","analyzedAt":"2026-08-04T20:26:47.563Z","schemaVersion":2}