go-redis/redis · error
redis: tx pipeline produced no outcome
Error message
redis: tx pipeline produced no outcome
What it means
A defensive fatal outcome raised in the cluster tx-pipeline path when, after running the connection-acquire closure and checking hook results, the outcome variable is still nil. It marks a logic gap where neither success, retry, redirect, nor an earlier error classified the result. Under normal operation it should be unreachable.
Source
Thrown at osscluster.go:2429
// Connection acquisition failed — fn never ran.
if shouldRetry(err, true) && !cmdsContainNoRetry(cmds) {
outcome = &txOutcome{kind: txRetryConn, err: err}
} else {
outcome = &txOutcome{kind: txFatal, err: err}
}
}
return err
})
if !executed && chainErr != nil {
// A node-level hook aborted with an error: surface its verdict. A hook
// that returned nil short-circuited successfully (it served the batch),
// which is legal for plain pipelines too, so it is not turned into a
// fatal outcome (review finding by codex on #3942).
outcome = &txOutcome{kind: txFatal, err: chainErr}
}
if outcome == nil {
outcome = &txOutcome{kind: txFatal, err: fmt.Errorf("redis: tx pipeline produced no outcome")}
}
return outcome
}
func (c *ClusterClient) processTxPipelineNodeConn(
ctx context.Context, node *clusterNode, cn *pool.Conn, wire []Cmder, cmds []Cmder, asking bool,
) *txOutcome {
// HIMPORT bookkeeping: pending discards and PREPAREs for registered
// fieldsets the transaction references get written ahead of the wire
// batch (before ASKING/MULTI; the session state is visible at EXEC).
injected := node.Client.himportInjectedCmds(ctx, cn, cmds)
if err := cn.WithWriter(c.context(ctx), c.opt.WriteTimeout, func(wr *proto.Writer) error {
for _, ic := range injected {
if err := writeCmd(wr, ic); err != nil {
return err
}
}View on GitHub (pinned to 36d97525cd)
Solutions
- Report it as a go-redis bug with the command sequence and hook configuration that triggered it.
- Temporarily simplify or remove custom ProcessHook/ProcessPipelineHook to see if the path resolves.
- Downgrade to a known-good go-redis version while the regression is investigated.
Defensive patterns
Strategy: try-catch
Try / catch
if err := cmd.Err(); err != nil && strings.Contains(err.Error(), "tx pipeline produced no outcome") {
// retry the tx once; if it persists, file a go-redis issue with hooks/cmd details
} Prevention
- Pin a known-good go-redis version in go.mod.
- Minimise custom ProcessHook/ProcessPipelineHook that can short-circuit outcomes.
- Reproduce with hooks disabled before reporting.
When it happens
Trigger: Triggered only by an internal inconsistency in tx-pipeline outcome classification (e.g. a hook short-circuit path that does not set an outcome). Not something application input can target directly.
Common situations: Seen after upgrading go-redis if a regression leaves an unhandled code path, or with a custom hook that returns in a way the classifier does not expect. Essentially a bug sentinel.
Related errors
- redis: unexpected EXEC reply %q
- redis: FT.CURSOR command requires at least 3 arguments
- redis: invalid cursor ID type
- redis: cannot pipeline command %q with request policy ReqAll
- redis: expected '*', but got line %q
AI-assisted analysis of go-redis/redis@36d97525cd (2026-08-06).
Data as JSON: /data/errors/30514e88f4f6591b.json.
Report an issue: GitHub.