etcd-io/etcd · error

cannot call Else twice!

Error message

cannot call Else twice!

What it means

The txn builder panics with 'cannot call Else twice!' when Else() is called more than once on the same Txn. A transaction has a single else-branch; the celse flag turns a second Else into a fail-fast panic before any request is serialized. All else-ops must be passed together in one call.

Source

Thrown at client/v3/txn.go:125

		panic("cannot call Then after Else!")
	}

	txn.cthen = true

	for _, op := range ops {
		txn.isWrite = txn.isWrite || op.isWrite()
		txn.sus = append(txn.sus, op.toRequestOp())
	}

	return txn
}

func (txn *txn) Else(ops ...Op) Txn {
	txn.mu.Lock()
	defer txn.mu.Unlock()

	if txn.celse {
		panic("cannot call Else twice!")
	}

	txn.celse = true

	for _, op := range ops {
		txn.isWrite = txn.isWrite || op.isWrite()
		txn.fas = append(txn.fas, op.toRequestOp())
	}

	return txn
}

func (txn *txn) Commit() (*TxnResponse, error) {
	txn.mu.Lock()
	defer txn.mu.Unlock()

	r := &pb.TxnRequest{Compare: txn.cmps, Success: txn.sus, Failure: txn.fas}

View on GitHub (pinned to f744d457f4)

Solutions

  1. Pass all else-ops in a single call: Else(op1, op2, ...)
  2. Collect []clientv3.Op for the fallback branch and call Else(ops...) once
  3. Refactor helpers to return Op slices instead of chaining on a shared Txn
  4. For genuinely separate fallback transactions, use separate Txn instances

Example fix

// before
t := cli.Txn(ctx).If(c).Then(a).Else(clientv3.OpPut("x", "1"))
t = t.Else(clientv3.OpPut("y", "2")) // panics

// after
t := cli.Txn(ctx).If(c).Then(a).Else(
	clientv3.OpPut("x", "1"),
	clientv3.OpPut("y", "2"),
)
Defensive patterns

Strategy: validation

Validate before calling

// One Else, all fallback ops together:
var elseOps []clientv3.Op
for _, k := range fallbackKeys {
	elseOps = append(elseOps, clientv3.OpPut(k, "v"))
}
t := cli.Txn(ctx).If(c).Then(a).Else(elseOps...)

Prevention

When it happens

Trigger: Calling t.Else(op1).Else(op2) on one Txn; loops that invoke Else per operation; multiple subsystems each adding fallback operations to a shared Txn instance.

Common situations: Code where fallback branches accumulate from several conditions or modules; translating nested if/else chains into one transaction; refactors splitting an Else call without collecting the ops into a slice.

Related errors


AI-assisted analysis of etcd-io/etcd@f744d457f4 (2026-08-15). Data as JSON: /api/errors/920e6b162c9fa162. Report an issue: GitHub.