getsops/sops · error

Found key %q in encrypted data, which starts with the reserv

Error message

Found key %q in encrypted data, which starts with the reserved key prefix %q for SOPS metadata

What it means

Raised by SerializeMetadata when user data contains a key that begins with the reserved `sops_` prefix while MetadataFlattenFull is active (flat metadata shares the same namespace as data keys). Emitting such a file would make metadata keys indistinguishable from data keys, so sops refuses.

Source

Thrown at stores/metadata.go:309

			}
		}
	}
	if opts.Flatten != MetadataFlattenFull {
		md = sops.TreeBranch{
			sops.TreeItem{
				Key:   SopsMetadataKey,
				Value: md,
			},
		}
	}
	var result sops.TreeBranches
	for _, branch := range data.Branches {
		newBranch := make(sops.TreeBranch, 0, len(branch)+len(md))
		for _, item := range branch {
			if key, ok := item.Key.(string); ok {
				if opts.Flatten == MetadataFlattenFull {
					if strings.HasPrefix(key, SopsPrefix) {
						return nil, fmt.Errorf("Found key %q in encrypted data, which starts with the reserved key prefix %q for SOPS metadata", key, SopsPrefix)
					}
				} else {
					if key == SopsMetadataKey {
						return nil, fmt.Errorf("Found key %q in encrypted data, which is a reserved key used for SOPS metadata", key)
					}
				}
			}
			newBranch = append(newBranch, item)
		}
		for _, item := range md {
			newBranch = append(newBranch, item)
		}
		result = append(result, newBranch)
	}
	return result, nil
}

View on GitHub (pinned to 13442bb981)

Solutions

  1. Rename the data key so it does not start with `sops_` (or `SOPS_` in env files)
  2. Store the value under a different name, e.g. `cfg_sops_settings` instead of `sops_settings`
  3. If the key must keep its name, use a format that stores metadata in a nested `sops` mapping (json/yaml stores) instead of flattening
  4. Filter out reserved-prefix keys before encrypting if they are not needed in the encrypted output

Example fix

// before: env file
SOPS_CONFIG_URL=https://example.com
// after: avoid reserved sops_ prefix in flattened stores
MYAPP_SOPS_CONFIG_URL=https://example.com
Defensive patterns

Strategy: validation

Validate before calling

func hasReservedKeys(tree sops.Tree, prefix string) []string {
	var bad []string
	for _, branch := range tree.Branches {
		for _, item := range branch {
			if k, ok := item.Key.(string); ok && strings.HasPrefix(k, prefix) {
				bad = append(bad, k)
			}
		}
	}
	return bad
}
if bad := hasReservedKeys(tree, "sops_"); len(bad) > 0 {
	return fmt.Errorf("rename reserved-prefixed keys before encrypting: %v", bad)
}

Type guard

func isReservedKey(k interface{}, prefix string) bool {
	s, ok := k.(string)
	return ok && strings.HasPrefix(s, prefix)
}

Try / catch

out, err := stores.SerializeMetadata(tree, opts)
if err != nil {
	if strings.Contains(err.Error(), "reserved key prefix") {
		return fmt.Errorf("rename keys starting with sops_ before encrypting with flattened metadata: %w", err)
	}
	return err
}

Prevention

When it happens

Trigger: Calling SerializeMetadata (or EmitEncryptedFile with an env/dotenv store) on a tree whose branches contain a string key starting with `sops_`, e.g. `sops_config`, `sops_env_var`, when Flatten is MetadataFlattenFull.

Common situations: Env/dotenv files containing variables literally named `SOPS_...` (common in CI configs referencing SOPS_* environment variables) being encrypted with the env store, or scripts generating keys prefixed with sops_.

Related errors


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