mikefarah/yq · error

HCL encoder expects a mapping at the root level, got %v

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'.

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 nil

View on GitHub (pinned to 8b5af0694b)

Solutions

  1. Ensure the root is an object: wrap with `{...}` or select a map, e.g. `yq -o hcl '{resource: .}'`
  2. Rebuild the expression so it yields a mapping, e.g. `yq -o hcl '{"my_block": .}'`
  3. 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

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


AI-assisted analysis of mikefarah/yq@8b5af0694b (2026-09-05). Data as JSON: /api/errors/81c0570a4c6089de. Report an issue: GitHub.