nats-io/nats-server · error

duplicate entry for %q

Error message

duplicate entry for %q

What it means

This function builds weighted cluster/subject mappings (e.g. service imports or weight mappings). It rejects duplicate destination subjects within a single mapping definition: if two destination entries share the same Subject string, it fails with this error naming the duplicated subject.

Source

Thrown at server/accounts.go:808

	return a.AddWeightedMappings(src, NewMapDest(dest, 100))
}

// AddWeightedMappings will add in a weighted mappings for the destinations.
func (a *Account) AddWeightedMappings(src string, dests ...*MapDest) error {
	a.mu.Lock()
	defer a.mu.Unlock()

	if !IsValidSubject(src) {
		return ErrBadSubject
	}

	m := &mapping{src: src, wc: subjectHasWildcard(src), dests: make([]*destination, 0, len(dests)+1)}
	seen := make(map[string]struct{})

	var tw = make(map[string]uint8)
	for _, d := range dests {
		if _, ok := seen[d.Subject]; ok {
			return fmt.Errorf("duplicate entry for %q", d.Subject)
		}
		seen[d.Subject] = struct{}{}
		if d.Weight > 100 {
			return fmt.Errorf("individual weights need to be <= 100")
		}
		tw[d.Cluster] += d.Weight
		if tw[d.Cluster] > 100 {
			return fmt.Errorf("total weight needs to be <= 100")
		}
		err := ValidateMapping(src, d.Subject)
		if err != nil {
			return err
		}
		tr, err := NewSubjectTransform(src, d.Subject)
		if err != nil {
			return err
		}
		if d.Cluster == _EMPTY_ {

View on GitHub (pinned to 3a66a489d2)

Solutions

  1. Deduplicate the dests slice by Subject before building the mapping (keep last/first occurrence per policy)
  2. Find and merge the duplicate source in config (server config, operator config, resolver) so each subject appears once
  3. If duplicates are intentional (multiple weights), aggregate them into a single entry with summed weights instead of separate entries

Example fix

// before
dests := []Destination{{Subject: "a"}, {Subject: "a"}}
m, err := buildMapping(src, dests) // duplicate entry for "a"
// after
dests = dedupeBySubject(dests)
m, err := buildMapping(src, dests)
Defensive patterns

Strategy: validation

Validate before calling

seen := make(map[string]struct{})
for _, d := range dests {
    if _, dup := seen[d.Subject]; dup {
        return fmt.Errorf("duplicate subject %q in mapping %q", d.Subject, src)
    }
    seen[d.Subject] = struct{}{}
}

Try / catch

m, err := buildMapping(src, dests)
if err != nil {
    var dupSubj string
    if n, _ := fmt.Sscanf(err.Error(), "duplicate entry for %q", &dupSubj); n == 1 {
        return fmt.Errorf("config error: subject %q defined multiple times in mapping", dupSubj)
    }
    return err
}

Prevention

When it happens

Trigger: Passing a dests slice to the mapping builder where two entries have identical d.Subject values — typically from merging config sources that each contributed the same account/subject, or duplicated entries in server config (accounts/imports/exports lists).

Common situations: Overlapping config snippets (operator config + resolver) that both define the same mapping destination; copy-pasted account import entries; automated config generation concatenating lists without deduplication.

Related errors


AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02). Data as JSON: /api/errors/15cd1b967d2334a8. Report an issue: GitHub.