Redis Error Guide: 'ERR MULTI calls can not be nested' — Fix Transaction State on Pooled Connections
Fix ERR MULTI calls can not be nested in Redis: diagnose a second MULTI on an open transaction, leaked state, and connection-pool reuse bugs.
- #redis
- #troubleshooting
- #errors
- #transactions
Stuck on this Redis error? Get the free incident triage checklist
A one-page PDF — the exact steps to isolate, fix, and verify a production error like this one. No spam, unsubscribe anytime.
Overview
Redis returns MULTI calls can not be nested when a MULTI command is issued on a connection that is already inside a transaction block. A Redis transaction is a flat sequence — MULTI opens it, commands queue, and EXEC/DISCARD closes it. There is no nesting; a second MULTI before the first is closed is an error.
The literal error clients receive:
(error) ERR MULTI calls can not be nested
Because transaction state is per connection, this almost always means the same connection issued two MULTIs without an intervening EXEC/DISCARD — often because a pooled connection was handed out mid-transaction, or an earlier EXEC was skipped after an exception.
Symptoms
MULTIfails intermittently under concurrency, but works in isolation.- Preceded by an earlier error or exception that skipped the matching
EXEC/DISCARD. - More frequent as pool size shrinks or load rises (connection reuse).
redis-cli MULTI
OK
redis-cli MULTI # same connection, still open
(error) ERR MULTI calls can not be nested
Common Root Causes
1. Leaked transaction state on a pooled connection
An exception was thrown after MULTI but before EXEC, the connection went back to the pool still “in MULTI”, and the next borrower issued MULTI again.
2. Application-level nested transactions
Two code paths each open a transaction on the same connection object (e.g. a helper calls MULTI, then the caller also calls MULTI).
3. Missing EXEC/DISCARD on an error branch
A try opened MULTI and the error path returned without DISCARD, leaving the connection dirty.
4. Manual MULTI mixed with a client’s pipeline/transaction helper
Calling raw MULTI while also using the library’s pipeline(transaction=True) on the same connection double-opens the block.
How to diagnose
Step 1: Check whether the connection thinks it is in a transaction
INFO clients shows connections currently inside MULTI.
redis-cli INFO clients | grep -E 'connected_clients|blocked_clients'
redis-cli CLIENT LIST | grep -E 'multi=[1-9]'
A multi= value greater than -1 means that client has queued transaction commands.
Step 2: Reproduce the leak path
Trace the code that runs MULTI and confirm every branch (including exceptions) reaches EXEC or DISCARD.
Step 3: Watch the command stream briefly
redis-cli MONITOR
... "MULTI"
... "SET" "a" "1"
... "MULTI" <- second MULTI, no EXEC between them
Run MONITOR only for a short window; it loads the server.
Step 4: Confirm pool reuse is the vector
If the error correlates with pool exhaustion, log the connection id (CLIENT ID) at MULTI and EXEC to prove the same connection was reused mid-transaction.
Fixes
Always pair MULTI with EXEC or DISCARD, including on errors
r = pool.get_connection()
try:
r.execute_command("MULTI")
r.execute_command("SET", "a", "1")
r.execute_command("EXEC")
except Exception:
r.execute_command("DISCARD") # clean up before returning to pool
raise
Prefer the client’s transaction/pipeline helper
Let the library manage MULTI/EXEC so state cannot leak:
with r.pipeline(transaction=True) as pipe:
pipe.set("a", 1)
pipe.incr("counter")
pipe.execute() # MULTI ... EXEC handled for you
Reset a dirty connection
If a connection may be in an unknown state, DISCARD (ignore its error if not in MULTI) or close it so the pool creates a fresh one.
redis-cli DISCARD
Never share one connection across concurrent transactions
Give each concurrent unit of work its own connection from the pool.
What to watch out for
- Transaction state is per connection, not per key or per client library object — pooling is where it bites.
DISCARDon a connection that is not inMULTIreturnsERR DISCARD without MULTI; guard your cleanup or ignore that specific error.- Redis transactions are not rollback transactions — a command that fails at
EXECdoes not undo earlier ones. Nesting confusion often hides deeper transaction-model misunderstandings. CLIENT LIST’smulti=field is the fastest live signal that a connection is stuck open.
Related
- Redis Error: ‘ERR DISCARD without MULTI’
- Redis Error: ‘ERR EXEC without MULTI’
- Redis Error: ‘EXECABORT Transaction discarded because of previous errors’
Paste the failing command into the free incident assistant, and browse more Redis guides.
Fixed it? Get 500 Redis & DevOps AI prompts — free
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.
Did this fix your issue?
Get 500 Battle-Tested DevOps AI Prompts — Free
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.