mikefarah/yq · error
HCL encoder expects a mapping at the root level, got
Error message
HCL encoder expects a mapping at the root level, got %v
What it means
The HCL format is structurally a set of blocks and attributes, so yq's HCL encoder requires the root node to be a mapping (object). Scalars or sequences at the root cannot be represented as HCL documents and trigger this error, which is then wrapped as 'failed to encode HCL'.
Solutions
- Ensure the root is an object: wrap with `{...}` or select a map, e.g. `yq -o hcl '{resource: .}'`
- Rebuild the expression so it yields a mapping, e.g. `yq -o hcl '{"my_block": .}'`
- Use JSON or YAML output for non-mapping data
Example fix
// before: yq -o hcl '.some_list'
// after: yq -o hcl '{block: .some_list}' Defensive patterns
Strategy: validation
Validate before calling
yq 'type == "!!map"' input.yaml # must print true before -o hcl
Type guard
func isHclEncodableRoot(node *CandidateNode) bool { return node.Kind == MappingNode } Try / catch
err := he.encodeNode(body, node)
if err != nil && strings.Contains(err.Error(), "expects a mapping at the root") {
// wrap the data in a top-level object and retry
} Prevention
- Wrap scalars/lists in `{key: ...}` before `-o hcl`
- Verify the expression output is an object (`type == "!!map"`)
- Remember HCL documents are blocks/attributes: root must be a map
When it happens
Trigger: `yq -o hcl '"just a string"'` or `yq -o hcl '[1,2,3]'` — encodeNode sees Kind != MappingNode at the root and returns this error via kindToString(node.Kind).
Common situations: Piping expressions that emit a single scalar/list into `-o hcl`; forgetting that HCL output needs `key: value` object shape at top level; converting JSON arrays of resources without wrapping them in a map.
Related errors
- expected mapping node for block body
- csv encoding only works for arrays, got
- failed to encode HCL
- HCL encoder does not support aliases
- unsupported character
AI-assisted analysis of mikefarah/yq@8b5af0694b (2026-09-05).
Data as JSON: /api/errors/81c0570a4c6089de.
Report an issue: GitHub.
Appendix: source
Thrown at pkg/yqlib/encoder_hcl.go:495
// If all child values are mappings, treat each child key as a labelled instance of this block type
if handled, _ := he.encodeMappingChildrenAsBlocks(body, key, valueNode); handled {
return true
}
// No labels detected, render as unlabelled block
block := body.AppendNewBlock(key, nil)
if err := he.encodeNodeAttributes(block.Body(), valueNode); err == nil {
return true
}
return false
}
// encodeNode encodes a CandidateNode directly to HCL, preserving style information
func (he *hclEncoder) encodeNode(body *hclwrite.Body, node *CandidateNode) error {
if node.Kind != MappingNode {
return fmt.Errorf("HCL encoder expects a mapping at the root level, got %v", kindToString(node.Kind))
}
for i := 0; i < len(node.Content); i += 2 {
keyNode := node.Content[i]
valueNode := node.Content[i+1]
key := keyNode.Value
// Render as block or attribute depending on value type
if he.encodeBlockIfMapping(body, key, valueNode) {
continue
}
// Render as attribute: key = value
if err := he.encodeAttribute(body, key, valueNode); err != nil {
return err
}
}
return nilView on GitHub (pinned to 8b5af0694b)