etcd-io/etcd · error
cannot call Then twice!
Error message
cannot call Then twice!
What it means
The txn builder panics with 'cannot call Then twice!' when Then() is called more than once on the same Txn. A transaction has exactly one then-branch; the cthen flag makes a second Then a grammar violation that fails fast with a panic before any request is built. Combine all then-ops in a single call — they run atomically.
Source
Thrown at client/v3/txn.go:104
panic("cannot call If after Else!")
}
txn.cif = true
for i := range cs {
cmp := cs[i].Clone()
txn.cmps = append(txn.cmps, cmp.GetCompare())
}
return txn
}
func (txn *txn) Then(ops ...Op) Txn {
txn.mu.Lock()
defer txn.mu.Unlock()
if txn.cthen {
panic("cannot call Then twice!")
}
if txn.celse {
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()View on GitHub (pinned to f744d457f4)
Solutions
- Pass all then-ops in one call: Then(op1, op2, ...) — they execute atomically on success
- Collect []clientv3.Op in a slice and call Then(ops...) once
- Change helpers to return Op values instead of mutating the Txn
- If you truly need two sequential transactions, create two separate Txn instances
Example fix
// before
t := cli.Txn(ctx).If(c).Then(clientv3.OpPut("a", "1"))
t = t.Then(clientv3.OpPut("b", "2")) // panics
// after
t := cli.Txn(ctx).If(c).Then(
clientv3.OpPut("a", "1"),
clientv3.OpPut("b", "2"),
) Defensive patterns
Strategy: validation
Validate before calling
// Collect then-ops, single Then call:
var thenOps []clientv3.Op
for _, k := range keys {
thenOps = append(thenOps, clientv3.OpPut(k, "v"))
}
t := cli.Txn(ctx).If(c).Then(thenOps...) Prevention
- One Then per Txn; all ops in one slice
- Helpers return Op, not chained Then calls
- Separate Txn instances for sequential transactions
When it happens
Trigger: Calling t.Then(op1).Then(op2) on one Txn, or appending then-ops incrementally from multiple helper functions. Loops that call Then per operation instead of passing an ops slice once.
Common situations: Accumulating write operations across code layers; translating SQL-style logic where multiple update statements were sequential; refactors that split one Then call into several without collecting ops first.
Related errors
- cannot call If twice!
- cannot call Else twice!
- cannot call If after Then!
- cannot call If after Else!
- cannot call Then after Else!
AI-assisted analysis of etcd-io/etcd@f744d457f4 (2026-08-15).
Data as JSON: /api/errors/2399b38f4ed05a39.
Report an issue: GitHub.