AdguardTeam/AdGuardHome · critical

adding client %q at index %d: %w

Error message

adding client %q at index %d: %w

What it means

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.

Source

Thrown at internal/client/storage.go:195

	s = &Storage{
		logger:                 conf.Logger,
		mu:                     &sync.Mutex{},
		index:                  newIndex(),
		runtimeIndex:           newRuntimeIndex(),
		upstreamManager:        newUpstreamManager(conf.BaseLogger, conf.Clock),
		dhcp:                   conf.DHCP,
		etcHosts:               conf.EtcHosts,
		arpDB:                  conf.ARPDB,
		done:                   make(chan struct{}),
		allowedTags:            tags,
		arpClientsUpdatePeriod: conf.ARPClientsUpdatePeriod,
		runtimeSourceDHCP:      conf.RuntimeSourceDHCP,
	}

	for i, p := range conf.InitialClients {
		err = s.Add(ctx, p)
		if err != nil {
			return nil, fmt.Errorf("adding client %q at index %d: %w", p.Name, i, err)
		}
	}

	s.ReloadARP(ctx)

	return s, nil
}

// type check
var _ service.Interface = (*Storage)(nil)

// Start implements the [service.Interface] for *Storage.  It starts the
// goroutines for updating the runtime client information.
func (s *Storage) Start(ctx context.Context) (err error) {
	go s.periodicARPUpdate(ctx)
	go s.handleHostsUpdates(ctx)

	return nil

View on GitHub (pinned to b41aefbe51)

Solutions

  1. Look at the wrapped error to see the actual cause and the client name/index from the message
  2. Fix or remove the offending client at that index in InitialClients and restart
  3. Validate the whole client list (uniqueness of IDs/IP/MAC, upstream parsing, known tags) before handing it to NewStorage

Example fix

// before
conf.InitialClients = []aghclient.PersistentClient{
  {Name: "a", IP: "10.0.0.1"},
  {Name: "b", IP: "10.0.0.1"}, // duplicate -> NewStorage fails at index 1
}

// after
conf.InitialClients = []aghclient.PersistentClient{
  {Name: "a", IP: "10.0.0.1"},
  {Name: "b", IP: "10.0.0.2"},
}
Defensive patterns

Strategy: validation

Validate before calling

for i := range conf.InitialClients {
    if err := validateClient(&conf.InitialClients[i]); err != nil { return fmt.Errorf("initial client %d: %w", i, err) }
}
// plus duplicate-ID/IP/MAC checks across the list

Try / catch

s, err := client.NewStorage(ctx, conf)
if err != nil && strings.Contains(err.Error(), "adding client") { /* log, fall back to empty storage or last good config */ }

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of AdguardTeam/AdGuardHome@b41aefbe51 (2026-08-27). Data as JSON: /api/errors/167ce8db9b039b71. Report an issue: GitHub.