{"record":{"id":"167ce8db9b039b71","repo":"AdguardTeam/AdGuardHome","slug":"adding-client-q-at-index-d-w","errorCode":null,"errorMessage":"adding client %q at index %d: %w","messagePattern":"adding client %q at index (.+?): %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"internal/client/storage.go","lineNumber":195,"sourceCode":"\ts = &Storage{\n\t\tlogger:                 conf.Logger,\n\t\tmu:                     &sync.Mutex{},\n\t\tindex:                  newIndex(),\n\t\truntimeIndex:           newRuntimeIndex(),\n\t\tupstreamManager:        newUpstreamManager(conf.BaseLogger, conf.Clock),\n\t\tdhcp:                   conf.DHCP,\n\t\tetcHosts:               conf.EtcHosts,\n\t\tarpDB:                  conf.ARPDB,\n\t\tdone:                   make(chan struct{}),\n\t\tallowedTags:            tags,\n\t\tarpClientsUpdatePeriod: conf.ARPClientsUpdatePeriod,\n\t\truntimeSourceDHCP:      conf.RuntimeSourceDHCP,\n\t}\n\n\tfor i, p := range conf.InitialClients {\n\t\terr = s.Add(ctx, p)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"adding client %q at index %d: %w\", p.Name, i, err)\n\t\t}\n\t}\n\n\ts.ReloadARP(ctx)\n\n\treturn s, nil\n}\n\n// type check\nvar _ service.Interface = (*Storage)(nil)\n\n// Start implements the [service.Interface] for *Storage.  It starts the\n// goroutines for updating the runtime client information.\nfunc (s *Storage) Start(ctx context.Context) (err error) {\n\tgo s.periodicARPUpdate(ctx)\n\tgo s.handleHostsUpdates(ctx)\n\n\treturn nil","sourceCodeStart":177,"sourceCodeEnd":213,"githubUrl":"https://github.com/AdguardTeam/AdGuardHome/blob/b41aefbe51c8dde65e2c50f093996afa0502edf9/internal/client/storage.go#L177-L213","documentation":"Constructor error from NewStorage: one of the InitialClients in the supplied configuration failed to be added, and the error is wrapped with the client's name and its position in the list. The inner error is typically one of the clash or validation errors from Add.","triggerScenarios":"Passing conf.InitialClients containing an invalid client (bad upstreams, unknown tag) or one that clashes with an earlier entry (duplicate ClientID, IP, subnet, or MAC). The failure index in the message points at the offending element.","commonSituations":"Loading a hand-edited or migrated YAML config with duplicated IPs/MACs, stale tags after a settings change, or upstream typos; first startup after editing clients in the config file.","solutions":["Look at the wrapped error to see the actual cause and the client name/index from the message","Fix or remove the offending client at that index in InitialClients and restart","Validate the whole client list (uniqueness of IDs/IP/MAC, upstream parsing, known tags) before handing it to NewStorage"],"exampleFix":"// before\nconf.InitialClients = []aghclient.PersistentClient{\n  {Name: \"a\", IP: \"10.0.0.1\"},\n  {Name: \"b\", IP: \"10.0.0.1\"}, // duplicate -> NewStorage fails at index 1\n}\n\n// after\nconf.InitialClients = []aghclient.PersistentClient{\n  {Name: \"a\", IP: \"10.0.0.1\"},\n  {Name: \"b\", IP: \"10.0.0.2\"},\n}","handlingStrategy":"validation","validationCode":"for i := range conf.InitialClients {\n    if err := validateClient(&conf.InitialClients[i]); err != nil { return fmt.Errorf(\"initial client %d: %w\", i, err) }\n}\n// plus duplicate-ID/IP/MAC checks across the list","typeGuard":null,"tryCatchPattern":"s, err := client.NewStorage(ctx, conf)\nif err != nil && strings.Contains(err.Error(), \"adding client\") { /* log, fall back to empty storage or last good config */ }","preventionTips":["Lint the whole client list before startup","Keep the previous config file so a failed constructor can fall back to it"],"tags":["storage","constructor","startup","config"],"backgroundTag":"invalid-initial-config","analyzedSha":"b41aefbe51c8dde65e2c50f093996afa0502edf9","analyzedAt":"2026-08-27T04:57:55.097Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}