getsops/sops · error
invalid %s key configuration: expected string in list, got %
Error message
invalid %s key configuration: expected string in list, got %T
What it means
parseKeyField accepts a string, []string, or nil for a key-group field; this error fires when a YAML list element is not a string (e.g. a map or number) while processing %s key configuration. It names the offending element's Go type to help locate the bad entry in the config file.
Source
Thrown at config/config.go:251
return []string{}, nil
}
// Existing CSV parsing logic
keys := strings.Split(v, ",")
result := make([]string, 0, len(keys))
for _, key := range keys {
trimmed := strings.TrimSpace(key)
if trimmed != "" { // Skip empty strings (fixes trailing comma issue)
result = append(result, trimmed)
}
}
return result, nil
case []interface{}:
result := make([]string, len(v))
for i, item := range v {
if str, ok := item.(string); ok {
result[i] = str
} else {
return nil, fmt.Errorf("invalid %s key configuration: expected string in list, got %T", fieldName, item)
}
}
return result, nil
case []string:
return v, nil
default:
return nil, fmt.Errorf("invalid %s key configuration: expected string, []string, or nil, got %T", fieldName, field)
}
}
func NewStoresConfig() *StoresConfig {
storesConfig := &StoresConfig{}
storesConfig.JSON.Indent = -1
storesConfig.JSONBinary.Indent = -1
return storesConfig
}
// Load loads a sops config file into a temporary structView on GitHub (pinned to 13442bb981)
Solutions
- Make every list entry a plain quoted string (e.g. `- age1abc...`, `- arn:aws:kms:...` as a single string)
- Quote entries that YAML would parse as numbers or booleans
- Inspect the exact line indicated by the field name and %T in the message to find the non-string element
Example fix
# before age: - recipient: age1abc... # map, not string # after age: - "age1abc..." # plain string entry
Defensive patterns
Strategy: validation
Validate before calling
// validate that all entries under a key field are plain strings
func isStringList(v interface{}) bool {
switch l := v.(type) {
case []interface{}:
for _, item := range l { if _, ok := item.(string); !ok { return false } }
return true
case []string, string, nil:
return true
}
return false
} Type guard
func asStringList(field interface{}) ([]string, bool) {
switch v := field.(type) {
case string: return []string{v}, true
case []string: return v, true
case []interface{}:
r := make([]string, 0, len(v))
for _, it := range v {
s, ok := it.(string); if !ok { return nil, false }
r = append(r, s)
}
return r, true
}
return nil, false
} Try / catch
keys, err := cfg.GetAgeKeys(creationRuleIndex)
if err != nil {
if strings.Contains(err.Error(), "expected string in list") {
return fmt.Errorf("fix .sops.yaml: every list entry must be a quoted plain string: %w", err)
}
return err
} Prevention
- Write key entries as plain quoted strings, never inline maps
- Quote values YAML would treat as numbers/booleans
- Run a YAML linter over .sops.yaml before committing
- Copy key-list syntax from sops documentation examples, not from other tools' configs
When it happens
Trigger: A config list entry like `age: - {recipient: age1...}` or `- 123` is passed to parseKeyField via GetAgeKeys/GetKMSKeys/GetPGPKeys/etc., where an item is not a plain string.
Common situations: Copy-pasting KMS-style structured entries (arn maps) into an age/pgp list, YAML indentation accidentally nesting a mapping inside a string list, quoting mistakes turning entries into numbers or booleans (e.g. unquoted 12345).
Related errors
- invalid %s key configuration: expected string, []string, or
- Could not unmarshal config file: %s
- invalid %s key configuration: %w
- config file not found
- error loading config: %s
AI-assisted analysis of getsops/sops@13442bb981 (2026-09-01).
Data as JSON: /api/errors/3e63bd7f4161bdf2.
Report an issue: GitHub.