hashicorp/nomad · error
failed to decode key %q to string
Error message
failed to decode key %q to string
What it means
parseKeyringConfigs decodes keyring provider blocks into a map, then for each key listed in the provider's ExtraKeysHCL asserts the decoded value is a string before copying it into provider.Config. This error names the key whose decoded value was not a string (e.g. a number, bool, or list).
Source
Thrown at command/agent/config_parse.go:639
}
for idx, obj := range keyringBlocks.Items {
provider := c.KEKProviders[idx]
if len(provider.ExtraKeysHCL) == 0 {
continue
}
provider.Config = map[string]string{}
var m map[string]any
if err := hcl.DecodeObject(&m, obj.Val); err != nil {
return err
}
for _, extraKey := range provider.ExtraKeysHCL {
val, ok := m[extraKey].(string)
if !ok {
return fmt.Errorf("failed to decode key %q to string", extraKey)
}
provider.Config[extraKey] = val
}
// clear the extra keys for these blocks because we've already handled
// them and don't want them to bubble up to the caller
provider.ExtraKeysHCL = nil
}
sort.Slice(c.KEKProviders, func(i, j int) bool {
return c.KEKProviders[i].ID() < c.KEKProviders[j].ID()
})
return nil
}
View on GitHub (pinned to 482b49bf1a)
Solutions
- Quote the offending key's value so HCL decodes it as a string: `kms_key_id = "12345"`
- Check the key name in the error message (%q) and locate it in the keyring block
- Flatten lists to a comma-separated string if the provider expects one value
- Confirm against the provider docs which keys are extra keys requiring string values
Example fix
// before
keyring {
provider = "awskms"
kms_key_id = 12345
}
// after
keyring {
provider = "awskms"
kms_key_id = "12345"
} Defensive patterns
Strategy: validation
Validate before calling
func assertKeyringExtraKeysAreStrings(keyring map[string]any, extraKeys []string) error {
for _, k := range extraKeys {
if v, present := keyring[k]; present {
if _, ok := v.(string); !ok {
return fmt.Errorf("keyring key %q must be a string, got %T", k, v)
}
}
}
return nil
} Type guard
func isString(v any) bool {
_, ok := v.(string)
return ok
} Try / catch
cfg, err := ParseConfigFile(path)
if err != nil {
if strings.Contains(err.Error(), "failed to decode key") {
return fmt.Errorf("keyring extra key must be a quoted string in %s: %w", path, err)
}
return err
} Prevention
- Quote all extra-key values in keyring blocks (numbers, bools, lists all fail)
- Keep numbers like key IDs as quoted strings
- After upgrading versions, re-check which keys are ExtraKeysHCL strings
- Type-check decoded keyring maps in a pre-parse validation step
When it happens
Trigger: A keyring block containing an extra key (one handled specially by the provider, listed in ExtraKeysHCL) with a non-string HCL value, e.g. `region = ["us-east-1"]` or `kms_key_id = 12345`, reached via ParseConfigFile/LoadConfig.
Common situations: Unquoted numbers/booleans in keyring provider config (AWS region lists, key IDs); schema drift between vault versions where a key moved into ExtraKeysHCL and now must be a string; templating that interpolates non-string types.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- error parsing 'keyring': %w
- error parsing: root should be an object
- error parsing 'vault': %w
- error parsing 'consul': %w
- should be an object
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/ddd3c03e27723b95.
Report an issue: GitHub.