go-redis/redis · critical

redis: NewClient nil options

Error message

redis: NewClient nil options

What it means

NewClient panics with 'redis: NewClient nil options' when the passed *Options pointer is nil. The constructor deliberately panics (documented at redis.go:1918) rather than returning an error because a client with no options has no Addr, no pool, and cannot function - it is a programmer error, not a runtime condition. The panic surfaces immediately at startup instead of producing confusing failures on the first command.

Source

Thrown at redis.go:1921

	*baseClient
	cmdable

	// cscLifecycleOwner keeps the canonical Client wrapper (the one whose GC
	// cleanup owns the drainer) reachable while a WithTimeout clone can still
	// serve from its cache. Nil on the canonical wrapper and on non-CSC clones.
	cscLifecycleOwner *Client

	autopipelinerMu     *sync.Mutex    // guards the autopipeliner fields against concurrent first-call creation
	autopipeliner       *AutoPipeliner // blocking face (Client.AutoPipeline)
	asyncAutopipeliner  *AutoPipeliner // deferred face (Client.AsyncAutoPipeline)
	autopipelinerClosed bool           // set by Close: refuse to resurrect a pipeliner on a closed client
}

// NewClient returns a client to the Redis Server specified by Options.
// Passing nil Options will cause a panic.
func NewClient(opt *Options) *Client {
	if opt == nil {
		panic("redis: NewClient nil options")
	}
	// clone to not share options with the caller
	opt = opt.clone()
	opt.init()

	// Push notifications are always enabled for RESP3 (cannot be disabled)

	c := Client{
		baseClient: &baseClient{
			apClosed: &atomic.Bool{},
			opt:      opt,
			onClose:  &onCloseHooks{},
			himport:  newHImportRegistry(),
		},
	}
	c.init()

	// Initialize push notification processor using shared helper

View on GitHub (pinned to 36d97525cd)

Solutions

  1. Ensure the *redis.Options passed to NewClient is always non-nil - construct it inline with &redis.Options{Addr: ...} at minimum.
  2. If options come from a loader/builder, have it always return a valid *redis.Options (defaulting fields) and never nil; add a unit test asserting non-nil.
  3. Guard the call site: if opt == nil { opt = &redis.Options{Addr: "localhost:6379"} } before NewClient, or return an error from your own factory.
  4. Run go vet / staticcheck to catch obviously-nil pointers; add a constructor wrapper that fails fast with a clear error instead of a panic.

Example fix

// before
client := redis.NewClient(optFromConfig) // optFromConfig is nil

// after
opt := optFromConfig
if opt == nil {
    opt = &redis.Options{Addr: "localhost:6379"}
}
client := redis.NewClient(opt)
Defensive patterns

Strategy: validation

Validate before calling

func newClient(opt *redis.Options) (*redis.Client, error) {
    if opt == nil {
        return nil, errors.New("redis options must not be nil")
    }
    if opt.Addr == "" {
        opt.Addr = "localhost:6379"
    }
    return redis.NewClient(opt), nil
}

Type guard

// Guard against a typed-nil or unset pointer before constructing.
func validOptions(opt *redis.Options) bool {
    return opt != nil
}

Try / catch

// Go has no catch; use recover at a goroutine boundary only as a last resort.
defer func() {
    if r := recover(); r != nil {
        log.Fatalf("redis client init failed: %v", r)
    }
}()
client := redis.NewClient(opt)

Prevention

When it happens

Trigger: Calling redis.NewClient(nil); passing a *redis.Options variable that was declared but never initialized (still nil); loading options from a builder/config function that returns nil on an unhandled branch; conditionally constructing options where the nil case is not covered.

Common situations: Config loaded from environment/flags where no values were set so the builder returns nil; DI containers or factories that return a typed nil (*redis.Options)(nil); tests that stub the options loader to return nil; refactoring that moves option construction behind a helper which forgets to initialize the struct.

Related errors


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