getsops/sops · error
Found key collision %q while flattening
Error message
Found key collision %q while flattening
What it means
While flattening, every leaf value gets a unique joined path key (e.g. "sops__map_metadata"). flattenDescendValue checks destinationMap before inserting a leaf; if the same path key was already written, this error fires because two different values would silently overwrite each other in the flat map.
Source
Thrown at stores/flatten.go:213
}
if tb, ok := result.(sops.TreeBranch); ok {
return tb, nil
}
return nil, fmt.Errorf("Internal error: cannot find root")
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Flatten
func flattenDescendValue(value interface{}, key string, destination sops.TreeBranch, destinationMap *map[string]bool) (sops.TreeBranch, error) {
switch value := value.(type) {
case sops.TreeBranch:
return flattenDescendMap(value, key+mapSeparator, destination, destinationMap)
case []interface{}:
return flattenDescendArray(value, key+listSeparator, destination, destinationMap)
}
if _, ok := (*destinationMap)[key]; ok {
return nil, fmt.Errorf("Found key collision %q while flattening", key)
}
destination = append(destination, sops.TreeItem{
Key: key,
Value: value,
})
(*destinationMap)[key] = true
return destination, nil
}
func flattenDescendMap(branch sops.TreeBranch, prefix string, destination sops.TreeBranch, destinationMap *map[string]bool) (sops.TreeBranch, error) {
for _, item := range branch {
if _, ok := item.Key.(sops.Comment); ok {
continue
}
if key, ok := item.Key.(string); ok {
var err error
destination, err = flattenDescendValue(item.Value, prefix+key, destination, destinationMap)
if err != nil {View on GitHub (pinned to 13442bb981)
Solutions
- Find and remove/rename the duplicate key in the source tree so each flattened path is unique
- Avoid using the literal substrings __map_ and __list_ in your configuration keys, or rename one of the colliding keys
- Deduplicate branches before calling flatten (e.g. build a set of keys and reject duplicates at load time)
Example fix
// before
branch := sops.TreeBranch{
{Key: "a", Value: "x"},
{Key: "a", Value: "y"}, // duplicate -> collision
}
// after
branch := sops.TreeBranch{
{Key: "a", Value: "x"},
{Key: "a2", Value: "y"},
} Defensive patterns
Strategy: validation
Validate before calling
keys := map[string]int{}
for _, item := range branch {
k := fmt.Sprintf("%v", item.Key)
keys[k]++
if keys[k] > 1 {
return fmt.Errorf("duplicate key %q in branch", k)
}
} Try / catch
flat, err := flattenTreeBranch(branch, "")
if err != nil {
var coll string
if n, _ := fmt.Sscanf(err.Error(), "Found key collision %q", &coll); n == 1 {
return fmt.Errorf("rename colliding key %s", coll)
}
return err
} Prevention
- Never include __map_ or __list_ literals in your config keys
- Reject duplicate keys when loading documents
- Deduplicate programmatically-built branches before flattening
When it happens
Trigger: Flattening a TreeBranch that contains two entries resolving to the same flattened path — e.g. a map key "a" with scalar value AND a deeper branch whose joined path produces the identical key, or duplicate keys at the same level such as {"a": 1, "a": 2} in the branch.
Common situations: INI-adjacent workflows where keys with dots or the literal separators __map_ / __list_ in user data collide with generated separator paths; programmatic tree construction that appended the same key twice; parsing formats that allow duplicate keys (e.g. INI with AllowNonUniqueSections) then flattening for metadata serialization.
Related errors
- Found non-string key %q when unflattening
- Error while unflattening: %w
- Found non-string key %q when flattening
- Failed to read %q: %w
- Internal error: cannot find root
AI-assisted analysis of getsops/sops@13442bb981 (2026-09-01).
Data as JSON: /api/errors/894d14607e68185d.
Report an issue: GitHub.