semaphoreui/semaphore · error

is duplicate

Error message

%s is duplicate

What it means

verifyDuplicate counts how many items in a backup entity list share the given name and fails if the name appears more than once (n > 2 counts the scan; more than one matching entry means duplication). Backup.Verify calls it to guarantee names are unique within each entity collection so name-based cross-references resolve unambiguously during restore.

Solutions

  1. Deduplicate the offending array in the backup JSON so each name appears exactly once (keeping the newest entry).
  2. Rename duplicates to unique names and update all references (e.g. inventory.ssh_key) to the new name.
  3. Re-export the backup after fixing uniqueness constraints at the source.
  4. Run Verify before Restore and fix all reported duplicate names in one pass.

Example fix

// before
"secret_storage": [{"name": "aws"}, {"name": "aws"}]
// after
"secret_storage": [{"name": "aws"}, {"name": "aws-eu"}]
Defensive patterns

Strategy: validation

Validate before calling

func hasDuplicates[T interface{ GetName() string }](items []T) bool {
    seen := map[string]bool{}
    for _, it := range items {
        if seen[it.GetName()] { return true }
        seen[it.GetName()] = true
    }
    return false
}
// run over keys, inventories, templates, repositories, secret_storages before Verify

Try / catch

if err := backup.Verify(); err != nil {
    if strings.Contains(err.Error(), "is duplicate") {
        // deduplicate the named entity in the backup JSON
    }
    return err
}

Prevention

When it happens

Trigger: Calling BackupFormat.Verify (BackupSecretStorage.Verify and siblings) on a backup whose entity arrays (e.g. secret_storage, keys, inventories) contain two or more entries with the same name.

Common situations: Backups merged from multiple exports or environments; manual concatenation of JSON arrays; database with non-unique names restored from a legacy system; duplicated blocks from a bad copy-paste edit.

Related errors


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

Appendix: source

Thrown at services/project/restore.go:30

	if name == nil {
		return nil
	}
	for _, o := range items {
		if o.GetName() == *name {
			return &o
		}
	}
	return nil
}

func verifyDuplicate[T BackupEntry](name string, items []T) error {
	n := 0
	for _, o := range items {
		if o.GetName() == name {
			n++
		}
		if n > 2 {
			return fmt.Errorf("%s is duplicate", name)
		}
	}
	return nil
}

func (e BackupSecretStorage) Verify(backup *BackupFormat) error {
	return verifyDuplicate[BackupSecretStorage](e.Name, backup.SecretStorages)
}

func (e BackupSecretStorage) Restore(b *BackupDB) error {
	st := e.SecretStorage
	st.ProjectID = b.meta.ID
	newStorage, err := b.store.CreateSecretStorage(st)
	if err != nil {
		return err
	}
	b.secretStorages = append(b.secretStorages, newStorage)
	return nil

View on GitHub (pinned to 1774ccb71a)