AdguardTeam/AdGuardHome · error

another client %q uses the same ClientID %q

Error message

another client %q uses the same ClientID %q

What it means

Thrown when adding or updating a persistent client whose ClientID collides with a different client already in the storage index. The index maps each ClientID to a unique UID, so two distinct clients cannot share a ClientID. The error names the conflicting client and the duplicated ID.

Source

Thrown at internal/client/index.go:117

		return fmt.Errorf("another client %q uses the same uid", p.Name)
	}

	return nil
}

// clashes returns an error if the index contains a different persistent client
// with at least a single identifier contained by c.  c must be non-nil.
func (ci *index) clashes(c *Persistent) (err error) {
	if p := ci.clashesName(c); p != nil {
		return fmt.Errorf("another client uses the same name %q", p.Name)
	}

	for _, id := range c.ClientIDs {
		existing, ok := ci.clientIDToUID[id]
		if ok && existing != c.UID {
			p := ci.uidToClient[existing]

			return fmt.Errorf("another client %q uses the same ClientID %q", p.Name, id)
		}
	}

	p, ip := ci.clashesIP(c)
	if p != nil {
		return fmt.Errorf("another client %q uses the same IP %q", p.Name, ip)
	}

	p, s := ci.clashesSubnet(c)
	if p != nil {
		return fmt.Errorf("another client %q uses the same subnet %q", p.Name, s)
	}

	p, mac := ci.clashesMAC(c)
	if p != nil {
		return fmt.Errorf("another client %q uses the same MAC %q", p.Name, mac)
	}

View on GitHub (pinned to b41aefbe51)

Solutions

  1. Inspect the stored clients and find the client named in the error message; remove the duplicated ID from one of the two clients
  2. If the two entries should be the same client, update the existing one instead of adding a new one
  3. Deduplicate ClientIDs across the whole initial client list before passing it to NewStorage

Example fix

// before
client.ClientIDs = []string{"alice"} // already used by client "laptop"
_ = s.Add(ctx, client)

// after
client.ClientIDs = []string{"alice-laptop"}
_ = s.Add(ctx, client)
Defensive patterns

Strategy: validation

Validate before calling

func hasClientIDClash(persistent []client.Persistent, c client.Persistent) bool {
    for _, p := range persistent {
        if p.UID == c.UID { continue }
        for _, id := range c.ClientIDs {
            if slices.Contains(p.ClientIDs, id) { return true }
        }
    }
    return false
}

Try / catch

err := s.Add(ctx, c)
if err != nil && strings.Contains(err.Error(), "uses the same ClientID") {
    // resolve conflict or fall back to Update on existing client
}

Prevention

When it happens

Trigger: Calling Storage.Add or Storage.Update (or the internal index clashes check) with a Client whose ClientIDs slice contains an ID already registered under another client's UID (i.e. a different Name/UID).

Common situations: Migrating or importing client lists that contain duplicate IDs (e.g. the same TLS CN or username appearing twice), copying a client configuration and forgetting to change its IDs, or UI edits that merge two clients into overlapping ID sets.

Related errors


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