semaphoreui/semaphore · error

duplicate key

Error message

duplicate key %s

What it means

ValueMap.appendValuesAndCheck detects duplicate entity keys when checkDuplicates is enabled. Two objects of the same type sharing the same scope+DbKey indicate corrupt or overlapping export data, so appending is aborted.

Solutions

  1. Deduplicate the values slice before appending (key by scope+GetDbKey)
  2. Verify the source store does not contain duplicate rows for the entity's DB key
  3. Reset or recreate the ValueMap if a prior load already inserted the same entities

Example fix

// before
chain.appendValues(values) // errors on second occurrence of key
// after
seen := map[EntityKey]bool{}
for _, v := range values {
    if !seen[v.GetDbKey()] {
        seen[v.GetDbKey()] = true
        chain.appendValues([]T{v})
    }
}
Defensive patterns

Strategy: try-catch

Validate before calling

seen := map[string]bool{}
for _, v := range values {
    k := scope + v.GetDbKey()
    if seen[k] { return fmt.Errorf("pre-check: duplicate %s", k) }
    seen[k] = true
}

Try / catch

err := valueMap.appendValues(values)
if err != nil {
    var dup string
    if n, _ := fmt.Sscanf(err.Error(), "duplicate key %s", &dup); n == 1 {
        log.Warnf("skipping duplicate %s", dup)
        return nil
    }
    return err
}

Prevention

When it happens

Trigger: Calling appendValues (which uses appendValuesAndCheck with duplicate checking) with a batch containing two EntityObject values whose GetDbKey() is identical within the same scope — e.g. loading the same entity twice or a store query returning duplicates.

Common situations: Database rows with duplicated logical keys; loading the same export file or entity set twice into one chain; buggy custom exporter emitting the same object multiple times.

Related errors


AI-assisted analysis of semaphoreui/semaphore@1774ccb71a (2026-09-07). Data as JSON: /api/errors/dd79f1a922a3434b. Report an issue: GitHub.

Appendix: source

Thrown at services/export/Exporter.go:258

		}
	}
	return keys, nil
}

func (t *ValueMap[T]) appendValues(values []T, scope string) error {
	return t.appendValuesAndCheck(values, scope, t.uniqueKeys)
}

func (t *ValueMap[T]) appendValuesAndCheck(values []T, scope string, checkDuplicates bool) error {
	if t.values == nil {
		t.keyScopeMap = make(map[string]bool)
		t.values = make([]EntityObject[T], 0)
	}
	for _, v := range values {
		if checkDuplicates {
			_, ok := t.keyScopeMap[scope+v.GetDbKey()]
			if ok {
				return fmt.Errorf("duplicate key %s", v.GetDbKey())
			}
			t.keyScopeMap[scope+v.GetDbKey()] = true
		}
		t.values = append(t.values, EntityObject[T]{value: v, scope: scope})
	}
	return nil
}

func (t *ValueMap[T]) exportDependsOn() []string {
	return []string{}
}

func (t *ValueMap[T]) importDependsOn() []string {
	return []string{}
}

func (t *ValueMap[T]) onError(err string) {
	if t.errs == nil {

View on GitHub (pinned to 1774ccb71a)