{"record":{"id":"4547849dce7bfaa7","repo":"redis/redis-py","slug":"commands-without-an-initial-watch-have-already-bee-454784","errorCode":null,"errorMessage":"Commands without an initial WATCH have already been issued","messagePattern":"Commands without an initial WATCH have already been issued","errorType":"exception","errorClass":"RedisError","httpStatus":null,"severity":"error","filePath":"redis/client.py","lineNumber":1891,"sourceCode":"        # we can safely return the connection to the pool here since we're\n        # sure we're no longer WATCHing anything\n        if self.connection:\n            self.connection_pool.release(self.connection)\n            self.connection = None\n\n    def close(self) -> None:\n        \"\"\"Close the pipeline\"\"\"\n        self.reset()\n\n    def multi(self) -> None:\n        \"\"\"\n        Start a transactional block of the pipeline after WATCH commands\n        are issued. End the transactional block with `execute`.\n        \"\"\"\n        if self.explicit_transaction:\n            raise RedisError(\"Cannot issue nested calls to MULTI\")\n        if self.command_stack:\n            raise RedisError(\n                \"Commands without an initial WATCH have already been issued\"\n            )\n        self.explicit_transaction = True\n\n    def execute_command(self, *args, **kwargs):\n        if (self.watching or args[0] == \"WATCH\") and not self.explicit_transaction:\n            return self.immediate_execute_command(*args, **kwargs)\n        return self.pipeline_execute_command(*args, **kwargs)\n\n    def _disconnect_reset_raise_on_watching(\n        self,\n        conn: AbstractConnection,\n        error: Exception,\n        failure_count: Optional[int] = None,\n        start_time: Optional[float] = None,\n        command_name: Optional[str] = None,\n    ) -> None:\n        \"\"\"","sourceCodeStart":1873,"sourceCodeEnd":1909,"githubUrl":"https://github.com/redis/redis-py/blob/6a6b581b48225afa0b76912d1028c6035baee932/redis/client.py#L1873-L1909","documentation":"Raised by Pipeline.multi() when self.command_stack is non-empty — meaning commands were already queued before MULTI. In redis-py's transaction model you must call WATCH (and multi()) before queuing any commands; queuing commands first then calling multi() indicates the user meant to use transaction=True implicitly or mis-ordered their calls.","triggerScenarios":"Calling pipe.set('k','v') (or any command) before pipe.multi(). The presence of entries in command_stack trips the guard at client.py:1890.","commonSituations":"Misunderstanding the manual transaction API order (multi must precede command queuing); migrating from pipeline(transaction=True) auto-mode to explicit multi() and getting the order wrong.","solutions":["Call pipe.multi() BEFORE queuing any commands (after optional WATCH).","Or construct the pipeline with transaction=True and let execute() handle MULTI/EXEC automatically — then you never call multi() yourself.","Reset the pipeline (pipe.reset()) and reorder if you queued commands prematurely."],"exampleFix":"// before\npipe = r.pipeline()\npipe.set('k', 'v')\npipe.multi()  # RedisError\n\n// after (explicit)\npipe = r.pipeline()\npipe.multi()\npipe.set('k', 'v')\npipe.execute()\n\n// after (implicit, preferred)\npipe = r.pipeline(transaction=True)\npipe.set('k', 'v')\npipe.execute()","handlingStrategy":"validation","validationCode":"if pipe.command_stack:\n    raise RuntimeError('Commands already queued; call multi() before queuing')\npipe.multi()","typeGuard":"def pipeline_ready_for_multi(pipe) -> bool:\n    return not pipe.command_stack and not pipe.explicit_transaction","tryCatchPattern":"from redis.exceptions import RedisError\ntry:\n    pipe.multi()\nexcept RedisError as e:\n    if 'without an initial WATCH' in str(e):\n        pipe.reset()\n        pipe.multi()  # retry in correct order\n    else:\n        raise","preventionTips":["Order: WATCH → read → multi() → queue → execute().","Use pipeline(transaction=True) to let the library manage MULTI placement.","Reset the pipeline if you queued commands before multi()."],"tags":["pipeline","transaction","api-misuse"],"backgroundTag":null,"analyzedSha":"6a6b581b48225afa0b76912d1028c6035baee932","analyzedAt":"2026-08-10T12:52:44.840Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}