mikefarah/yq · error

csv object encoding only works for arrays of flat objects (s

Error message

csv object encoding only works for arrays of flat objects (string key => string/numbers/boolean value), child[0] is a %v

What it means

In CSV object-encoding mode, yq derives the CSV header from the keys of the first element, which must be a mapping (flat object). This error is thrown when the first child of the sequence is not a mapping, so no header can be extracted.

Source

Thrown at pkg/yqlib/encoder_csv.go:60

}

func (e *csvEncoder) encodeArrays(csvWriter *csv.Writer, content []*CandidateNode) error {
	for i, child := range content {

		if child.Kind != SequenceNode {
			return fmt.Errorf("csv encoding only works for arrays of scalars (string/numbers/booleans), child[%v] is a %v", i, child.Tag)
		}
		err := e.encodeRow(csvWriter, child.Content)
		if err != nil {
			return err
		}
	}
	return nil
}

func (e *csvEncoder) extractHeader(child *CandidateNode) ([]*CandidateNode, error) {
	if child.Kind != MappingNode {
		return nil, fmt.Errorf("csv object encoding only works for arrays of flat objects (string key => string/numbers/boolean value), child[0] is a %v", child.Tag)
	}
	mapKeys := getMapKeys(child)
	return mapKeys.Content, nil
}

func (e *csvEncoder) createChildRow(child *CandidateNode, headers []*CandidateNode) []*CandidateNode {
	childRow := make([]*CandidateNode, 0)
	for _, header := range headers {
		keyIndex := findKeyInMap(child, header)
		value := createScalarNode(nil, "")
		if keyIndex != -1 {
			value = child.Content[keyIndex+1]
		}
		childRow = append(childRow, value)
	}
	return childRow

}

View on GitHub (pinned to 8b5af0694b)

Solutions

  1. Ensure the root is an array of objects: `[{k1: v1, k2: v2}, ...]`
  2. Convert scalars to objects, e.g. `yq 'map({value: .})'` before encoding
  3. Use row mode by making elements arrays of scalars instead

Example fix

// before: yq -o csv '["a","b"]'
// after:  yq -o csv '[{"name": "a"}, {"name": "b"}]'
Defensive patterns

Strategy: type-guard

Validate before calling

yq 'if (.[0] | type) == "!!map" then "ok" else "not-object-array" end' input.yaml

Type guard

func isObjectArray(node *CandidateNode) bool {
  return node.Kind == SequenceNode &&
    len(node.Content) > 0 &&
    node.Content[0].Kind == MappingNode
}

Try / catch

out, err := encodeCSV(node)
if err != nil && strings.Contains(err.Error(), "csv object encoding only works") {
    // fall back to wrapping data as array of objects or use JSON output
}

Prevention

When it happens

Trigger: `yq -o csv` on an array whose first element is a scalar or array instead of an object, e.g. `yq -o csv '["a","b"]'` or `[ [1,2], {a: 1} ]` — extractHeader sees child.Kind != MappingNode.

Common situations: Pointing yq at mixed-shape data; forgetting that object CSV mode requires an array of objects at the root; piping scalar lists where row mode (not object mode) was intended.

Related errors


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