go-redis/redis · error
redis: AutoPipelineOptions.AdaptiveDelay requires MaxFlushDe
Error message
redis: AutoPipelineOptions.AdaptiveDelay requires MaxFlushDelay > 0 (adaptive delay scales MaxFlushDelay by queue fill; with no MaxFlushDelay it would silently disable batch accumulation entirely)
What it means
Returned by AutoPipelineOptions.Validate() when AdaptiveDelay is enabled but MaxFlushDelay is zero or negative. AdaptiveDelay works by scaling MaxFlushDelay according to how full the queue is, so a zero MaxFlushDelay would collapse to zero delay on every flush and silently disable batch accumulation entirely. The library refuses the config at construction time rather than pretend to honor it.
Source
Thrown at autopipeline.go:240
// than being silently coerced to a default. Zero is allowed and means "use
// the default" (MaxBatchSize) or "no delay" (MaxFlushDelay).
if cfg.MaxBatchSize < 0 {
return fmt.Errorf("redis: AutoPipelineOptions.MaxBatchSize=%d must be >= 0", cfg.MaxBatchSize)
}
if cfg.MaxBatchBytes < 0 {
return fmt.Errorf("redis: AutoPipelineOptions.MaxBatchBytes=%d must be >= 0", cfg.MaxBatchBytes)
}
if cfg.MaxConcurrentBatches < 0 {
return fmt.Errorf("redis: AutoPipelineOptions.MaxConcurrentBatches=%d must be >= 0", cfg.MaxConcurrentBatches)
}
if cfg.MaxFlushDelay < 0 {
return fmt.Errorf("redis: AutoPipelineOptions.MaxFlushDelay=%s must be >= 0", cfg.MaxFlushDelay)
}
if cfg.NumShards < 0 {
return fmt.Errorf("redis: AutoPipelineOptions.NumShards=%d must be >= 0", cfg.NumShards)
}
if cfg.AdaptiveDelay && cfg.MaxFlushDelay <= 0 {
return fmt.Errorf("redis: AutoPipelineOptions.AdaptiveDelay requires MaxFlushDelay > 0 " +
"(adaptive delay scales MaxFlushDelay by queue fill; with no MaxFlushDelay it would " +
"silently disable batch accumulation entirely)")
}
return nil
}
// cmdableClient is an interface for clients that support pipelining.
// Both Client and ClusterClient implement this interface. It embeds
// UniversalClient (Cmdable + Process + Do + AddHook + Watch + Subscribe... +
// Close + PoolStats) so the AutoPipeliner can delegate the non-batched surface
// back to the underlying client and itself satisfy UniversalClient.
type cmdableClient interface {
UniversalClient
// processPipelineHook is the hook-wrapped []Cmder pipeline entry — the same
// method Pipeline.Exec is wired to (see Client.Pipeline). The flusher
// dispatches drained batches through it directly, skipping the per-batch
// Pipeline construction; hooks/OTel see the identical call.
processPipelineHook(ctx context.Context, cmds []Cmder) errorView on GitHub (pinned to 36d97525cd)
Solutions
- Set MaxFlushDelay to a small positive duration (e.g. 50*time.Microsecond or 1*time.Millisecond) alongside AdaptiveDelay: true.
- If you do not need adaptive batching, drop AdaptiveDelay (leave it false) and rely on the default backpressure-based coalescing.
- Run AutoPipelineOptions.Validate() explicitly in a unit test over your config struct so this surfaces before deploy.
Example fix
// before
opts := redis.AutoPipelineOptions{
AdaptiveDelay: true,
// MaxFlushDelay left zero
}
// after
opts := redis.AutoPipelineOptions{
AdaptiveDelay: true,
MaxFlushDelay: 200 * time.Microsecond,
} Defensive patterns
Strategy: validation
Validate before calling
if opts.AdaptiveDelay && opts.MaxFlushDelay <= 0 {
return fmt.Errorf("AdaptiveDelay needs a positive MaxFlushDelay (got %s)", opts.MaxFlushDelay)
}
if err := opts.Validate(); err != nil {
return err
} Prevention
- Always pair AdaptiveDelay with an explicit positive MaxFlushDelay.
- Call AutoPipelineOptions.Validate() in a unit test over your config struct.
- Treat config as code: review the full struct, not just the field you changed.
When it happens
Trigger: Constructing an AutoPipeliner (or calling AutoPipeline() on a client) with AutoPipelineOptions{AdaptiveDelay: true} while leaving MaxFlushDelay at its zero default (or setting it negative). The check at autopipeline.go:239 fires before any shard is created.
Common situations: Copy-pasting a config snippet that mentions AdaptiveDelay without the matching MaxFlushDelay; flipping AdaptiveDelay on while tuning other knobs; assuming AdaptiveDelay has a built-in default delay (it does not — it only scales an explicit MaxFlushDelay).
Related errors
- redis: AutoPipelineOptions.NumShards=%d requires Unordered:t
- redis: AutoPipeline is not supported by Ring
- redis: AutoPipelineOptions.MaxConcurrentBatches=%d requires
- redis: AutoPipelineOptions.MaxBatchSize=%d must be >= 0
- redis: AutoPipelineOptions.MaxBatchBytes=%d must be >= 0
AI-assisted analysis of go-redis/redis@36d97525cd (2026-08-06).
Data as JSON: /data/errors/942af52ae32f8ca2.json.
Report an issue: GitHub.