go-redis/redis · error

redis: cannot pipeline command %q with request policy ReqAll

Error message

redis: cannot pipeline command %q with request policy ReqAllNodes/ReqAllShards/ReqMultiShard; Note: This behavior is subject to change in the future

What it means

Returned by the autopipeline preflight (installAutoPipelineSharding) when a command whose request policy is ReqAllNodes, ReqAllShards, or ReqMultiShard is submitted through an AutoPipeline/AsyncAutoPipeline face on a ClusterClient. Such commands fan out across nodes and cannot be merged into a single-node batch, so they are rejected at submit before poisoning a coalesced batch.

Source

Thrown at osscluster.go:1692

// instead of splitting every batch across all nodes at flush. Cluster slots are
// contiguous per node, so bucketing by slot range (slot*shards/16384) keeps a
// node's slots together. Keyless commands hash to slot -1 → bucket 0; multi-node
// commands are already rejected from pipelines, so only single-node commands
// reach here.
func (c *ClusterClient) installAutoPipelineSharding(ap *AutoPipeliner) {
	// Reject commands whose request policy cannot ride a pipeline (ReqAllNodes/
	// ReqAllShards/ReqMultiShard) at submit, BEFORE they can join a merged
	// batch: mapCmdsByNode fails a whole mapping on such a command (user
	// pipelines are all-or-nothing), and one autopipeline caller must not be
	// able to poison unrelated callers' batches. Rejecting here also keeps the
	// lone-command fast path consistent with batched dispatch — the command is
	// refused regardless of what it happens to coalesce with.
	ap.setPreflight(func(ctx context.Context, cmd Cmder) error {
		if c.cmdInfoResolver == nil {
			return nil
		}
		if policy := c.cmdInfoResolver.GetCommandPolicy(ctx, cmd); policy != nil && !policy.CanBeUsedInPipeline() {
			return fmt.Errorf(
				"redis: cannot pipeline command %q with request policy ReqAllNodes/ReqAllShards/ReqMultiShard; Note: This behavior is subject to change in the future", cmd.Name(),
			)
		}
		return nil
	})
	// Commands whose routing is not slot-derived must not be coalesced: a solo
	// flush reaches ClusterClient.process and its special handling (FT.CURSOR
	// READ/DEL are sticky to the node holding the cursor), but inside a batch
	// mapCmdsByNode routes by slot and can hit the wrong shard — visible only
	// under concurrent traffic, which is the worst way to find it. Divert them
	// instead of rejecting: they work fine on their own connection (review
	// finding by codex on #3942).
	ap.setMustDivert(func(ctx context.Context, cmd Cmder) bool {
		if c.cmdInfoResolver == nil {
			return false
		}
		policy := c.cmdInfoResolver.GetCommandPolicy(ctx, cmd)
		return policy != nil && policy.Request == routing.ReqSpecial

View on GitHub (pinned to 36d97525cd)

Solutions

  1. Run fan-out commands directly on the cluster client (not through the AutoPipeline face).
  2. Use ClusterClient.Process or the dedicated helper for the operation instead of pipelining it.
  3. If you need it in a batch, split the work into per-slot commands that are single-node.

Example fix

// before
ap := client.AutoPipeline()
ap.Do(ctx, "FLUSHALL")
ap.Exec(ctx)
// after
client.Do(ctx, "FLUSHALL")
Defensive patterns

Strategy: try-catch

Validate before calling

func isFanOutCommand(ctx context.Context, c *redis.ClusterClient, cmd redis.Cmder) bool {
    // Heuristic: admin/aggregate names that the cluster router fans out.
    switch strings.ToUpper(cmd.Name()) {
    case "FLUSHALL", "FLUSHDB", "CONFIG", "INFO", "KEYS", "DBSIZE", "WAIT", "SCAN":
        return true
    }
    return false
}

Try / catch

err := ap.Do(ctx, "...").Err()
if err != nil && strings.Contains(err.Error(), "cannot pipeline command") {
    // re-issue directly on the cluster client outside the autopipeline
}

Prevention

When it happens

Trigger: Issuing a fan-out command (e.g. FLUSHALL, CONFIG GET, INFO across the cluster, or a multi-shard command) through client.AutoPipeline() on a ClusterClient. The error names the offending command via cmd.Name().

Common situations: Migrating standalone code to cluster + autopipelining without realising certain admin/aggregate commands are incompatible, or wrapping every call including cluster-wide ones in an autopipeline batch.

Related errors


AI-assisted analysis of go-redis/redis@36d97525cd (2026-08-06). Data as JSON: /data/errors/058fae4fe4dbb8c4.json. Report an issue: GitHub.