{"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/da03cdc7e8731092b13e395605c3c1fb2de25de1/redis/client.py#L1873-L1909","documentation":"Raised in `Pipeline.multi()` when `self.command_stack` is non-empty. The explicit-multi workflow requires WATCH (or nothing) to be issued before MULTI; queuing regular commands first and then calling `multi()` is rejected because those commands were already buffered as a non-transactional pipeline. The library refuses to silently convert a plain pipeline into a transaction.","triggerScenarios":"Calling `pipe.set('a', 1)` (or any command) BEFORE `pipe.multi()`. Once the command_stack has entries, multi() is disallowed. The correct order is: optional `pipe.watch(...)`, then `pipe.multi()`, then the queued commands.","commonSituations":"Misunderstanding the WATCH->MULTI->commands->EXEC ordering; refactoring a plain pipeline into a transactional one without moving the multi() call to the front.","solutions":["Reorder: issue `pipe.multi()` (after optional `pipe.watch(...)`) before queuing any commands.","If you intended a plain (non-transactional) pipeline, simply omit the multi() call — execute() will run the buffered commands.","Create a new pipeline if you need to switch from plain to transactional mode."],"exampleFix":"# before\npipe = client.pipeline()\npipe.set('a', 1)\npipe.multi()  # raises: Commands without an initial WATCH have already been issued\n\n# after\npipe = client.pipeline()\npipe.multi()\npipe.set('a', 1)\npipe.execute()","handlingStrategy":"validation","validationCode":"# Enforce ordering: multi() must precede any queued commands\npipe = client.pipeline()\npipe.multi()  # call BEFORE queuing commands\npipe.set('a', 1)","typeGuard":null,"tryCatchPattern":"from redis.exceptions import RedisError\ntry:\n    pipe.multi()\nexcept RedisError as e:\n    if 'Commands without an initial WATCH' in str(e):\n        # start over with a new pipeline in the correct order\n        pipe = client.pipeline(); pipe.multi()\n    else:\n        raise","preventionTips":["Always issue multi() before any command when you want a transaction.","Create a new pipeline if you need to switch modes."],"tags":["pipeline","transaction","ordering"],"analyzedSha":"da03cdc7e8731092b13e395605c3c1fb2de25de1","analyzedAt":"2026-08-04T20:26:47.563Z","schemaVersion":2}