etcd-io/etcd · error
cannot call Then after Else!
Error message
cannot call Then after Else!
What it means
The txn builder panics with 'cannot call Then after Else!' when Then() is called after Else() has already been declared on the same Txn. The grammar order is If -> Then -> Else; once the else-branch is set (celse flag), adding a then-branch is a construction bug and the builder panics immediately. Nothing has been committed when this fires.
Source
Thrown at client/v3/txn.go:107
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()
if txn.celse {
panic("cannot call Else twice!")View on GitHub (pinned to f744d457f4)
Solutions
- Reorder so Then(...) precedes Else(...) on the Txn
- Assemble thenOps and elseOps slices locally, then chain once: If(cs...).Then(thenOps...).Else(elseOps...)
- Do not mutate a Txn across helpers; build it in exactly one function
- Cover composite transactions with unit tests to catch chain-order regressions
Example fix
// before
t := cli.Txn(ctx).If(c).Else(clientv3.OpGet("k"))
t = t.Then(clientv3.OpPut("k", "v")) // panics
// after
t := cli.Txn(ctx).If(c).
Then(clientv3.OpPut("k", "v")).
Else(clientv3.OpGet("k")) Defensive patterns
Strategy: validation
Validate before calling
// Chain in canonical order, assembled from slices: t := cli.Txn(ctx).If(cmps...).Then(thenOps...).Else(elseOps...)
Prevention
- Then must precede Else
- Never append Then from a helper after Else
- Build the full chain in one function
When it happens
Trigger: Sequences like cli.Txn(ctx).Then(a).Else(b).Then(c), or cli.Txn(ctx).Else(b).Then(a) — any Then after an Else. Typically caused by reordered builder chains in refactored code or helpers appending then-ops after the else-branch was already supplied.
Common situations: Wrappers that let callers register then/else callbacks in arbitrary order; merges where a Then block got appended after the Else block; copy-paste insertion at the wrong position in a chain.
Related errors
- cannot call If after Then!
- cannot call If after Else!
- cannot call If twice!
- cannot call Then twice!
- cannot call Else twice!
AI-assisted analysis of etcd-io/etcd@f744d457f4 (2026-08-15).
Data as JSON: /api/errors/0556eca176c16b5a.
Report an issue: GitHub.