redis/redis-py · error · NotImplementedError

Method is not supported in transactional context.

Error message

Method is not supported in transactional context.

What it means

NotImplementedError from TransactionStrategy.mset_nonatomic (redis/asyncio/cluster.py:3349). mset_nonatomic is inherently a non-atomic multi-key operation; it is meaningless inside an atomic (MULTI/EXEC) transaction, so the transactional strategy refuses it. The method only exists on the non-atomic strategy.

Solutions

  1. Use the regular mset/mapping inside a transaction (all keys must share a slot)
  2. Drop the transaction and use the non-atomic pipeline strategy if you need mset_nonatomic
  3. Loop individual SET commands inside the transaction

Example fix

// before
pipe.multi()
pipe.mset_nonatomic({'a':1, 'b':2})
// after
pipe.multi()
pipe.mset({'a':1, 'b':2})  # keys must share a slot
Defensive patterns

Strategy: validation

Validate before calling

if pipe._execution_strategy.__class__.__name__ == 'TransactionStrategy':
    raise ValueError('mset_nonatomic is unsupported in a transaction; use mset')

Try / catch

try:
    pipe.mset_nonatomic(mapping)
except NotImplementedError:
    pipe.mset(mapping)  # inside transaction, same-slot keys only

Prevention

When it happens

Trigger: Calling `pipe.mset_nonatomic({...})` on a ClusterPipeline whose execution strategy is TransactionStrategy (i.e. inside `multi()`/transaction=True flow).

Common situations: Switching a pipeline from non-transactional to transactional and forgetting to replace mset_nonatomic with regular mset.

Related errors


AI-assisted analysis of redis/redis-py@6a6b581b48 (2026-08-10). Data as JSON: /api/errors/291124f02087d75b. Report an issue: GitHub.

Appendix: source

Thrown at redis/asyncio/cluster.py:3352

        for r, cmd in zip(responses, stack):
            if isinstance(r, Exception):
                self._annotate_exception(r, cmd.position + 1, cmd.args)

                await record_operation_duration(
                    command_name="TRANSACTION",
                    duration_seconds=time.monotonic() - start_time,
                    server_address=self._transaction_connection.host,
                    server_port=self._transaction_connection.port,
                    db_namespace=str(self._transaction_connection.db),
                    error=r,
                )

                raise r

    def mset_nonatomic(
        self, mapping: Mapping[AnyKeyT, EncodableT]
    ) -> "ClusterPipeline":
        raise NotImplementedError("Method is not supported in transactional context.")

    async def execute(
        self, raise_on_error: bool = True, allow_redirections: bool = True
    ) -> List[Any]:
        stack = self._command_queue
        if not stack and (not self._watching or not self._pipeline_slots):
            return []

        return await self._execute_transaction_with_retries(stack, raise_on_error)

    async def _execute_transaction_with_retries(
        self, stack: List["PipelineCommand"], raise_on_error: bool
    ):
        return await self._retry.call_with_retry(
            lambda: self._execute_transaction(stack, raise_on_error),
            lambda error, failure_count: self._reinitialize_on_error(
                error, failure_count
            ),

View on GitHub (pinned to 6a6b581b48)