{"id":"e13247cffa8b36bb","repo":"go-redis/redis","slug":"redis-no-sentinels-configured","errorCode":null,"errorMessage":"redis: no sentinels configured","messagePattern":"redis: no sentinels configured","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"sentinel.go","lineNumber":1000,"sourceCode":"\n\tif c.sentinel != nil {\n\t\taddr, err := c.getMasterAddr(ctx, c.sentinel)\n\t\tif err != nil {\n\t\t\t_ = c.closeSentinel()\n\t\t\tif isContextError(ctx.Err()) {\n\t\t\t\treturn \"\", err\n\t\t\t}\n\t\t\t// Continue on other errors\n\t\t\tinternal.Logger.Printf(ctx, \"sentinel: GetMasterAddrByName name=%q failed: %s\",\n\t\t\t\tc.opt.MasterName, err)\n\t\t} else {\n\t\t\treturn addr, nil\n\t\t}\n\t}\n\n\t// short circuit if no sentinels configured\n\tif len(c.sentinelAddrs) == 0 {\n\t\treturn \"\", errors.New(\"redis: no sentinels configured\")\n\t}\n\n\tvar (\n\t\tmasterAddr string\n\t\twg         sync.WaitGroup\n\t\tonce       sync.Once\n\t\terrCh      = make(chan error, len(c.sentinelAddrs))\n\t)\n\n\tctx, cancel := context.WithCancel(ctx)\n\tdefer cancel()\n\n\tfor i, sentinelAddr := range c.sentinelAddrs {\n\t\twg.Add(1)\n\t\tgo func(i int, addr string) {\n\t\t\tdefer wg.Done()\n\t\t\tsentinelCli := NewSentinelClient(c.opt.sentinelOptions(addr))\n\t\t\taddrVal, err := sentinelCli.GetMasterAddrByName(ctx, c.opt.MasterName).Result()","sourceCodeStart":982,"sourceCodeEnd":1018,"githubUrl":"https://github.com/go-redis/redis/blob/36d97525cd8076aed67cddf54778e9ea84550929/sentinel.go#L982-L1018","documentation":"Returned by the sentinel failover client when there are no sentinel addresses configured (c.sentinelAddrs is empty) after the initial sentinel lookup path fails to find a master. The failover client needs at least one Sentinel to discover the current master; with none configured it cannot proceed.","triggerScenarios":"Creating a FailoverClient with an empty SentinelAddrs slice and no MasterName-driven discovery. SentinelAddrs was set only on Options but the failover options path didn't receive them. A misconfigured SentinelOptions where the addrs slice is nil/empty.","commonSituations":"Configuring redis.NewFailoverClient with MasterName but forgetting SentinelAddrs. Environment/config loading that returns an empty address list (env var not set, config file parse error). Copy-paste errors omitting the SentinelAddrs field.","solutions":["Provide at least one sentinel address in FailoverOptions.SentinelAddrs (one per Sentinel instance).","Validate that the config source (env var, file) actually populated SentinelAddrs before constructing the client.","Add a startup assertion: if len(opts.SentinelAddrs) == 0 { return error }."],"exampleFix":"// before — MasterName set but no sentinels\nclient := redis.NewFailoverClient(&redis.FailoverOptions{\n    MasterName: \"mymaster\",\n    // SentinelAddrs missing/empty\n})\n// client.Get(ctx, \"k\").Err() => redis: no sentinels configured\n\n// after\nclient := redis.NewFailoverClient(&redis.FailoverOptions{\n    MasterName:   \"mymaster\",\n    SentinelAddrs: []string{\"sentinel-1:26379\", \"sentinel-2:26379\"},\n})","handlingStrategy":"validation","validationCode":"func validateFailoverOpts(o *redis.FailoverOptions) error {\n    if o.MasterName == \"\" {\n        return errors.New(\"MasterName is required\")\n    }\n    if len(o.SentinelAddrs) == 0 {\n        return errors.New(\"SentinelAddrs is empty; provide at least one sentinel host:port\")\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Assert len(FailoverOptions.SentinelAddrs) > 0 at startup.","Load-test config sources to ensure SentinelAddrs is populated in all environments.","Include MasterName and at least 2-3 Sentinel addresses for redundancy."],"tags":["sentinel","failover","configuration","bootstrap"],"analyzedSha":"36d97525cd8076aed67cddf54778e9ea84550929","analyzedAt":"2026-08-06T01:08:27.376Z","schemaVersion":2}