mikefarah/yq · error
expected mapping node for block body
Error message
expected mapping node for block body
What it means
When encoding HCL blocks, the body of a block must be a mapping of attributes/sub-blocks. This error is raised by encodeNodeAttributes (used by block and if-mapping encoding paths) when the node supplied as a block body is not a mapping, e.g. it is a scalar or sequence.
Source
Thrown at pkg/yqlib/encoder_hcl.go:589
labels := []string{childKey}
if extraLabels, bodyNode, ok := extractBlockLabels(childVal); ok {
labels = append(labels, extraLabels...)
childVal = bodyNode
}
block := body.AppendNewBlock(blockType, labels)
if err := he.encodeNodeAttributes(block.Body(), childVal); err != nil {
return true, err
}
}
}
return true, nil
}
// encodeNodeAttributes encodes the attributes of a mapping node (used for blocks)
func (he *hclEncoder) encodeNodeAttributes(body *hclwrite.Body, node *CandidateNode) error {
if node.Kind != MappingNode {
return fmt.Errorf("expected mapping node for block body")
}
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 attribute for non-block value
if err := he.encodeAttribute(body, key, valueNode); err != nil {
return err
}
}
return nilView on GitHub (pinned to 8b5af0694b)
Solutions
- Make the block body a mapping: `{resource: {aws_instance: {name: {...}}}}`
- Fix the input data so every block level is an object of attribute name => value
- Skip/reshape non-map entries with expressions like `del(.bad_block)` before `-o hcl`
Example fix
// before: {resource: {aws_instance: "web"}}
// after: {resource: {aws_instance: {web: {ami: "ami-123"}}}} Defensive patterns
Strategy: validation
Validate before calling
yq '[.. | tag] | any("!!seq" or "!!scalar" at block positions)' # or explicitly check each block:
yq '.resource | to_entries | all(.value | type == "!!map")' input.yaml Type guard
func blockBodiesAreMaps(root *CandidateNode) bool {
for i := 1; i < len(root.Content); i += 2 {
if root.Content[i].Kind != MappingNode { return false }
}
return true
} Try / catch
if err := he.encodeNodeAttributes(body, blockNode); err != nil {
if strings.Contains(err.Error(), "expected mapping node for block body") {
// reshape the block value into a mapping and retry
}
} Prevention
- Every HCL block level must be an object: name => {attributes}
- Validate nested block shapes with `to_entries | all(.value | type == "!!map")`
- Fix inputs where blocks accidentally map to scalars or lists
When it happens
Trigger: Encoding HCL where a block's value is a non-map, e.g. `{resource: {aws_instance: "oops"}}` — the innermost block body is a scalar, so encodeNodeAttributes returns 'expected mapping node for block body'.
Common situations: Terraform-style YAML where a resource block accidentally holds a list instead of an object; typos in config where block names map to scalars; generated data with inconsistent nesting depth.
Related errors
- HCL encoder expects a mapping at the root level, got %v
- failed to encode HCL: %w
- unsupported character %q in raw HCL expression
- HCL encoder does not support aliases
- unsupported node kind: %v
AI-assisted analysis of mikefarah/yq@8b5af0694b (2026-09-05).
Data as JSON: /api/errors/c2f28b9289a4cc9a.
Report an issue: GitHub.