Skip to content
DevOps AI ToolKit
Newsletter
All guides
AI for Redis By James Joyner IV · · 8 min read Last reviewed Jul 2026

Redis Error Guide: 'ERR MULTI calls can not be nested' — Fix Transaction State on Pooled Connections

Quick answer

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
Free toolkit

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

  • MULTI fails 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.
  • DISCARD on a connection that is not in MULTI returns ERR DISCARD without MULTI; guard your cleanup or ignore that specific error.
  • Redis transactions are not rollback transactions — a command that fails at EXEC does not undo earlier ones. Nesting confusion often hides deeper transaction-model misunderstandings.
  • CLIENT LIST’s multi= field is the fastest live signal that a connection is stuck open.

Paste the failing command into the free incident assistant, and browse more Redis guides.

Free download · 368-page PDF

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?

Free download · 368-page PDF

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.