{"record":{"id":"9dbe01131791ea3b","repo":"mikefarah/yq","slug":"cannot-get-keys-of-v-keys-only-works-for-maps-an","errorCode":null,"errorMessage":"cannot get keys of %v, keys only works for maps and arrays","messagePattern":"cannot get keys of (.+?), keys only works for maps and arrays","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/yqlib/operator_keys.go","lineNumber":54,"sourceCode":"\n}\n\nfunc keysOperator(_ *dataTreeNavigator, context Context, _ *ExpressionNode) (Context, error) {\n\tlog.Debugf(\"keysOperator\")\n\n\tvar results = list.New()\n\n\tfor el := context.MatchingNodes.Front(); el != nil; el = el.Next() {\n\t\tcandidate := el.Value.(*CandidateNode)\n\n\t\tvar targetNode *CandidateNode\n\t\tswitch candidate.Kind {\n\t\tcase MappingNode:\n\t\t\ttargetNode = getMapKeys(candidate)\n\t\tcase SequenceNode:\n\t\t\ttargetNode = getIndices(candidate)\n\t\tdefault:\n\t\t\treturn Context{}, fmt.Errorf(\"cannot get keys of %v, keys only works for maps and arrays\", candidate.Tag)\n\t\t}\n\n\t\tresults.PushBack(targetNode)\n\t}\n\n\treturn context.ChildContext(results), nil\n}\n\nfunc getMapKeys(node *CandidateNode) *CandidateNode {\n\tcontents := make([]*CandidateNode, 0)\n\tfor index := 0; index < len(node.Content); index = index + 2 {\n\t\tcontents = append(contents, node.Content[index])\n\t}\n\n\tseq := &CandidateNode{Kind: SequenceNode, Tag: \"!!seq\"}\n\tseq.AddChildren(contents)\n\treturn seq\n}","sourceCodeStart":36,"sourceCodeEnd":72,"githubUrl":"https://github.com/mikefarah/yq/blob/8b5af0694bb82b41d4ae180fac9972029066f90a/pkg/yqlib/operator_keys.go#L36-L72","documentation":"The `keys` (and `keys_unsorted`) operator returns the keys of a map or the indices of an array. For any other node kind (scalar or null), there is no meaningful key set, so the operator fails with this error, including the offending tag in the message. It exists to catch expressions applied to the wrong node type.","triggerScenarios":"Running `keys` on a scalar (`\"hello\" | keys`), on null (empty document or missing field), or on a selected field that turned out not to be a map/array.","commonSituations":"Assuming a YAML field is a map when it's a scalar; empty files producing null documents; optional config sections absent in some files; applying keys at the document root of a scalar-valued JSON.","solutions":["Verify the node kind first and branch: `select(kind == \"map\") | keys`","Provide defaults for missing data: `.cfg // {} | keys`","Select the actual map: `.settings | keys` instead of running keys on the root","Convert scalars to maps upstream if keys of a wrapper object were intended"],"exampleFix":"// before\n\"hello\" | keys\n// error: cannot get keys of !!str, keys only works for maps and arrays\n\n// after\n{a: 1, b: 2} | keys   # => [\"a\", \"b\"]","handlingStrategy":"type-guard","validationCode":"yq 'select(kind == \"map\" or kind == \"seq\")' input.yaml","typeGuard":"def keys_of(v):\n    return list(v.keys()) if isinstance(v, dict) else list(range(len(v))) if isinstance(v, list) else None","tryCatchPattern":"out=$(yq '.cfg // {} | keys' f.yaml 2>&1) || {\n  echo \"keys applied to non-map/non-array: $out\" >&2\n}","preventionTips":["Default optional sections: .section // {} | keys","Branch on kind before calling keys","Validate document shape of external inputs","Check that the field you select is actually a map/array"],"tags":["yq","keys","type-mismatch"],"backgroundTag":"keys-of-non-object","analyzedSha":"8b5af0694bb82b41d4ae180fac9972029066f90a","analyzedAt":"2026-09-05T10:57:22.766Z","contentChangedAt":"2026-09-05T10:57:22.766Z","schemaVersion":2},"datasetVersion":"2026-09-12T17:17:11.597Z"}