hashicorp/nomad · error
cannot check HCL keys of type %T
Error message
cannot check HCL keys of type %T
What it means
CheckHCLKeys validates that all keys of an HCL block belong to a set of valid key names. It only supports nodes that are *ast.ObjectList or *ast.ObjectType; if a caller passes any other ast.Node (e.g. *ast.LiteralType, *ast.ListType, nil), it returns this error naming the actual Go type. Nomad's parse functions (quota specs, storage/device resources, node pool limits, etc.) call it right after HCL decoding.
Source
Thrown at helper/funcs.go:249
clean := invalidFilenameNonASCII.ReplaceAllLiteralString(filename, replace)
return clean
}
// CleanFilenameStrict replaces invalid and punctuation characters in filename
func CleanFilenameStrict(filename string, replace string) string {
clean := invalidFilenameStrict.ReplaceAllLiteralString(filename, replace)
return clean
}
func CheckHCLKeys(node ast.Node, valid []string) error {
var list *ast.ObjectList
switch n := node.(type) {
case *ast.ObjectList:
list = n
case *ast.ObjectType:
list = n.List
default:
return fmt.Errorf("cannot check HCL keys of type %T", n)
}
validMap := make(map[string]struct{}, len(valid))
for _, v := range valid {
validMap[v] = struct{}{}
}
var result error
for _, item := range list.Items {
key := item.Keys[0].Token.Value().(string)
if _, ok := validMap[key]; !ok {
result = multierror.Append(result, fmt.Errorf(
"invalid key: %s", key))
}
}
return result
}View on GitHub (pinned to 482b49bf1a)
Solutions
- Pass the correct node: use the *ast.ObjectType from the parsed block (or its .List *ast.ObjectList) rather than a literal/list node
- Verify the caller obtained the node from hcl.Parse / the ObjectItem's Val (*ast.ObjectType) and not from decoding the value
- Guard for nil before calling CheckHCLKeys; a nil node also falls into the default branch
- If you genuinely need to validate other node kinds, extend the switch to handle them explicitly instead of hitting the default
Example fix
// before
node, _ := hcl.Parse(string(content))
// node is *ast.File, not an ObjectType
err := CheckHCLKeys(node, validKeys)
// after
objList, _ := hcl.Parse(string(content))
for _, item := range objList.Node.(*ast.ObjectList).Items {
if err := CheckHCLKeys(item.Val.(*ast.ObjectType), validKeys); err != nil {
return err
}
} Defensive patterns
Strategy: type-guard
Validate before calling
func isCheckableNode(n ast.Node) bool {
switch n.(type) {
case *ast.ObjectList, *ast.ObjectType:
return true
default:
return false
}
}
// call: if isCheckableNode(node) { CheckHCLKeys(node, valid) } Type guard
func isCheckableNode(n ast.Node) bool {
switch n.(type) {
case *ast.ObjectList, *ast.ObjectType:
return true
default:
return false
}
} Try / catch
if err := CheckHCLKeys(node, validKeys); err != nil {
if strings.HasPrefix(err.Error(), "cannot check HCL keys of type") {
return fmt.Errorf("bug: CheckHCLKeys called with non-object node: %w", err)
}
return err // invalid-key errors are real config problems
} Prevention
- Always pass the block's *ast.ObjectType (ObjectItem.Val) or the parsed *ast.ObjectList, never decoded values or literals
- Check for nil nodes before calling CheckHCLKeys
- When adding new HCL block parsers, mirror existing parse*Impl patterns that use CheckHCLKeys
- In tests, construct *ast.ObjectType fixtures rather than arbitrary ast.Node mocks
When it happens
Trigger: Calling CheckHCLKeys (directly or via parseQuotaSpecImpl, parseQuotaLimits, parseQuotaResource, parseStorageResource, parseDeviceResource, parseNodePoolLimit) with an ast.Node that is neither an *ast.ObjectList nor *ast.ObjectType — for example passing the result of decoding a bare literal or list, or a nil node.
Common situations: Custom Nomad forks/plugins adding new HCL block parsing that feeds the wrong AST node type into CheckHCLKeys; refactored parsers that pass a decoded value instead of the block's ObjectType; unit tests calling CheckHCLKeys with a mocked ast.Node.
Related errors
- failed to parse HCL file %s: %w
- error parsing: root should be an object
- failed to hcl parse the config: %v
- only one storage block is allowed
- <combined HCL diagnostics from str.String()>
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/7195d386f9edfcec.
Report an issue: GitHub.