{"record":{"id":"3b55aa7c33187fe4","repo":"getsops/sops","slug":"found-non-string-key-q-when-flattening","errorCode":null,"errorMessage":"Found non-string key %q when flattening","messagePattern":"Found non-string key %q when flattening","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"stores/flatten.go","lineNumber":235,"sourceCode":"\t\tValue: value,\n\t})\n\t(*destinationMap)[key] = true\n\treturn destination, nil\n}\n\nfunc flattenDescendMap(branch sops.TreeBranch, prefix string, destination sops.TreeBranch, destinationMap *map[string]bool) (sops.TreeBranch, error) {\n\tfor _, item := range branch {\n\t\tif _, ok := item.Key.(sops.Comment); ok {\n\t\t\tcontinue\n\t\t}\n\t\tif key, ok := item.Key.(string); ok {\n\t\t\tvar err error\n\t\t\tdestination, err = flattenDescendValue(item.Value, prefix+key, destination, destinationMap)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t} else {\n\t\t\treturn nil, fmt.Errorf(\"Found non-string key %q when flattening\", item.Key)\n\t\t}\n\t}\n\treturn destination, nil\n}\n\nfunc flattenDescendArray(array []interface{}, prefix string, destination sops.TreeBranch, destinationMap *map[string]bool) (sops.TreeBranch, error) {\n\ti := 0\n\tfor _, item := range array {\n\t\tif _, ok := item.(sops.Comment); ok {\n\t\t\tcontinue\n\t\t}\n\t\tvar err error\n\t\tdestination, err = flattenDescendValue(item, fmt.Sprintf(\"%s%d\", prefix, i), destination, destinationMap)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\ti++\n\t}","sourceCodeStart":217,"sourceCodeEnd":253,"githubUrl":"https://github.com/getsops/sops/blob/13442bb98183887d7a9ac09ec8ab0564673a59d8/stores/flatten.go#L217-L253","documentation":"flattenDescendMap walks a sops.TreeBranch and needs each TreeItem key to be a string so it can join path segments. Keys that are neither sops.Comment nor string (numbers, bools, nested structs) cannot be joined into the flattened path, so flattening aborts with this error.","triggerScenarios":"Calling flattenTreeBranch (directly or via stores.Flatten/MetadataFlattenBelowTop inside ExtractMetadata or ini EmitEncryptedFile's SerializeMetadata) on a branch where a nested item's Key is an int/bool/etc., e.g. sops.TreeItem{Key: 0, Value: ...} inside a subtree.","commonSituations":"Trees produced by other format stores that use numeric keys for arrays and were never converted; hand-assembled trees mixing types; passing a YAML/JSON-parsed branch straight into INI metadata serialization where array indices were left as ints.","solutions":["Convert all non-string keys to strings (fmt.Sprintf(\"%v\", key)) before flattening","Represent arrays as []interface{} values under a string key instead of numeric keys in the branch","Use sops.Comment{} for comment entries so they are skipped rather than rejected","Parse the document with the store matching its format so keys are normalized"],"exampleFix":"// before\nsops.TreeBranch{{Key: 0, Value: \"first\"}}\n\n// after\nsops.TreeBranch{{Key: \"items\", Value: []interface{}{\"first\"}}}","handlingStrategy":"type-guard","validationCode":"for _, item := range branch {\n\tif _, ok := item.Key.(sops.Comment); ok {\n\t\tcontinue\n\t}\n\tif _, ok := item.Key.(string); !ok {\n\t\treturn fmt.Errorf(\"nested key %v is not a string; cannot flatten\", item.Key)\n\t}\n}","typeGuard":"func allStringKeys(branch sops.TreeBranch) bool {\n\tfor _, item := range branch {\n\t\tif _, isComment := item.Key.(sops.Comment); isComment {\n\t\t\tcontinue\n\t\t}\n\t\tif _, ok := item.Key.(string); !ok {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}","tryCatchPattern":"flat, err := flattenTreeBranch(branch, \"\")\nif err != nil {\n\tif strings.Contains(err.Error(), \"non-string key\") {\n\t\treturn fmt.Errorf(\"normalize keys before flattening: %w\", err)\n\t}\n\treturn err\n}","preventionTips":["Represent arrays as []interface{} values, not numeric-keyed entries","Parse with the store matching the source format","Use sops.Comment{} for comments so they are skipped"],"tags":["go","sops","type-mismatch","flatten"],"backgroundTag":"invalid-key-type","analyzedSha":"13442bb98183887d7a9ac09ec8ab0564673a59d8","analyzedAt":"2026-09-01T03:53:00.447Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}