{"record":{"id":"1cc624624f2b6b73","repo":"getsops/sops","slug":"found-duplicate-v-entry","errorCode":null,"errorMessage":"Found duplicate %v entry","messagePattern":"Found duplicate (.+?) entry","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"stores/metadata.go","lineNumber":116,"sourceCode":"\tif err != nil {\n\t\treturn md, err\n\t}\n\terr = d.Decode(m)\n\treturn md, err\n}\n\n// ExtractMetadata extracts SOPS metadata from the supplied tree branches.\nfunc ExtractMetadata(branches sops.TreeBranches, opts MetadataOpts) (sops.TreeBranches, sops.Metadata, error) {\n\tvar metadataTree sops.TreeBranch\n\tif opts.Flatten != MetadataFlattenFull {\n\t\tfirst := true\n\t\tfor bi, branch := range branches {\n\t\t\ti := 0\n\t\t\tfor i < len(branch) {\n\t\t\t\tif branch[i].Key == SopsMetadataKey {\n\t\t\t\t\tif bi == 0 {\n\t\t\t\t\t\tif !first {\n\t\t\t\t\t\t\treturn nil, sops.Metadata{}, fmt.Errorf(\"Found duplicate %v entry\", SopsMetadataKey)\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfirst = false\n\t\t\t\t\t\tif tree, ok := branch[i].Value.(sops.TreeBranch); ok {\n\t\t\t\t\t\t\tmetadataTree = tree\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\treturn nil, sops.Metadata{}, fmt.Errorf(\"Found %v entry that is not a mapping\", SopsMetadataKey)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbranch = append(branch[:i], branch[i+1:]...)\n\t\t\t\t} else {\n\t\t\t\t\ti++\n\t\t\t\t}\n\t\t\t}\n\t\t\tbranches[bi] = branch\n\t\t}\n\t} else {\n\t\tif len(branches) >= 1 {\n\t\t\tbranch := branches[0]","sourceCodeStart":98,"sourceCodeEnd":134,"githubUrl":"https://github.com/getsops/sops/blob/13442bb98183887d7a9ac09ec8ab0564673a59d8/stores/metadata.go#L98-L134","documentation":"Raised by ExtractMetadata when the sops tree contains more than one `sops` metadata entry in the first branch. The parser expects exactly one nested `sops` mapping holding the encrypted-file metadata; a second one is ambiguous and treated as corruption.","triggerScenarios":"Calling LoadEncryptedFile (which calls ExtractMetadata) on a file that literally contains two `sops:` metadata blocks — e.g. from a merge conflict, a concatenation of two encrypted files, a bad re-encryption, or a user manually editing the file and duplicating the sops block.","commonSituations":"Git merge conflicts in encrypted files resolved incorrectly, scripts that append sops output to existing files, YAML/JSON files edited by hand where the sops key was re-added, or file corruption from interrupted writes.","solutions":["Open the file and remove the duplicate `sops` metadata block, keeping exactly one","Restore the file from git (git checkout -- file) or from backup if a merge corrupted it","Re-encrypt a known-good plaintext with sops instead of hand-repairing metadata","Validate the file structure with a JSON/YAML parser to spot duplicated top-level keys"],"exampleFix":"// before (file contains two sops blocks after a bad merge)\n{\"data\": \"ENC[AES256_GCM,...]\", \"sops\": {...}, \"sops\": {...}}\n// after: keep exactly one sops metadata block\n{\"data\": \"ENC[AES256_GCM,...]\", \"sops\": {\"mac\": \"...\", \"pgp\": [...]}}","handlingStrategy":"validation","validationCode":"func countSopsKeys(b []byte) (int, error) {\n\tvar m map[string]json.RawMessage\n\tif err := json.Unmarshal(b, &m); err != nil {\n\t\treturn 0, err\n\t}\n\treturn len(m[\"sops\"]), nil // >1 means duplicate risk in raw text; check raw text for key duplication\n}\n// for raw text: count occurrences of the top-level sops key before loading\ncount := strings.Count(string(data), `\"sops\": {`)","typeGuard":null,"tryCatchPattern":"tree, err := store.LoadEncryptedFile(data)\nif err != nil {\n\tif strings.Contains(err.Error(), \"Found duplicate sops entry\") {\n\t\treturn fmt.Errorf(\"file has more than one sops metadata block; resolve merge conflict or restore from git: %w\", err)\n\t}\n\treturn err\n}","preventionTips":["Never hand-edit the sops metadata block in encrypted files","Resolve git merge conflicts in encrypted files with a sops-aware merge driver or by re-encrypting from plaintext","Don't concatenate or append sops output to existing encrypted files"],"tags":["metadata","corruption","duplicate-key","sops"],"backgroundTag":"duplicate-sops-metadata-key","analyzedSha":"13442bb98183887d7a9ac09ec8ab0564673a59d8","analyzedAt":"2026-09-01T03:53:00.447Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}