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

  1. Find and remove/rename the duplicate key in the source tree so each flattened path is unique
  2. Avoid using the literal substrings __map_ and __list_ in your configuration keys, or rename one of the colliding keys
  3. 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

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


AI-assisted analysis of getsops/sops@13442bb981 (2026-09-01). Data as JSON: /api/errors/894d14607e68185d. Report an issue: GitHub.