{"record":{"id":"81cdb40d2002f77c","repo":"semaphoreui/semaphore","slug":"s-is-duplicate","errorCode":null,"errorMessage":"%s is duplicate","messagePattern":"(.+?) is duplicate","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"services/project/restore.go","lineNumber":30,"sourceCode":"\tif name == nil {\n\t\treturn nil\n\t}\n\tfor _, o := range items {\n\t\tif o.GetName() == *name {\n\t\t\treturn &o\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc verifyDuplicate[T BackupEntry](name string, items []T) error {\n\tn := 0\n\tfor _, o := range items {\n\t\tif o.GetName() == name {\n\t\t\tn++\n\t\t}\n\t\tif n > 2 {\n\t\t\treturn fmt.Errorf(\"%s is duplicate\", name)\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (e BackupSecretStorage) Verify(backup *BackupFormat) error {\n\treturn verifyDuplicate[BackupSecretStorage](e.Name, backup.SecretStorages)\n}\n\nfunc (e BackupSecretStorage) Restore(b *BackupDB) error {\n\tst := e.SecretStorage\n\tst.ProjectID = b.meta.ID\n\tnewStorage, err := b.store.CreateSecretStorage(st)\n\tif err != nil {\n\t\treturn err\n\t}\n\tb.secretStorages = append(b.secretStorages, newStorage)\n\treturn nil","sourceCodeStart":12,"sourceCodeEnd":48,"githubUrl":"https://github.com/semaphoreui/semaphore/blob/1774ccb71a0a8b82eb74ea24c23ac9ab713de2fa/services/project/restore.go#L12-L48","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Deduplicate the offending array in the backup JSON so each name appears exactly once (keeping the newest entry).","Rename duplicates to unique names and update all references (e.g. inventory.ssh_key) to the new name.","Re-export the backup after fixing uniqueness constraints at the source.","Run Verify before Restore and fix all reported duplicate names in one pass."],"exampleFix":"// before\n\"secret_storage\": [{\"name\": \"aws\"}, {\"name\": \"aws\"}]\n// after\n\"secret_storage\": [{\"name\": \"aws\"}, {\"name\": \"aws-eu\"}]","handlingStrategy":"validation","validationCode":"func hasDuplicates[T interface{ GetName() string }](items []T) bool {\n    seen := map[string]bool{}\n    for _, it := range items {\n        if seen[it.GetName()] { return true }\n        seen[it.GetName()] = true\n    }\n    return false\n}\n// run over keys, inventories, templates, repositories, secret_storages before Verify","typeGuard":null,"tryCatchPattern":"if err := backup.Verify(); err != nil {\n    if strings.Contains(err.Error(), \"is duplicate\") {\n        // deduplicate the named entity in the backup JSON\n    }\n    return err\n}","preventionTips":["Deduplicate exports before merging backups from multiple sources.","Enforce name uniqueness at the source database level.","Always run Verify before Restore in automation."],"tags":["backup-restore","validation","duplicate-entries"],"backgroundTag":"duplicate-entry-detected","analyzedSha":"1774ccb71a0a8b82eb74ea24c23ac9ab713de2fa","analyzedAt":"2026-09-07T11:00:33.293Z","contentChangedAt":"2026-09-07T11:00:33.293Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}