{"record":{"id":"ed721028868308d6","repo":"getsops/sops","slug":"internal-error-cannot-find-root","errorCode":null,"errorMessage":"Internal error: cannot find root","messagePattern":"Internal error: cannot find root","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"stores/flatten.go","lineNumber":199,"sourceCode":"\t\t}\n\t\tif key, ok := item.Key.(string); ok {\n\t\t\ttokens := tokenize(key)\n\t\t\terr := place(&item.Value, tokens, root)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"Error while unflattening %q: %w\", key, err)\n\t\t\t}\n\t\t} else {\n\t\t\treturn nil, fmt.Errorf(\"Found non-string key %q when unflattening\", item.Key)\n\t\t}\n\t}\n\tresult, err := convert(root)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"Error while unflattening: %w\", err)\n\t}\n\tif tb, ok := result.(sops.TreeBranch); ok {\n\t\treturn tb, nil\n\t}\n\treturn nil, fmt.Errorf(\"Internal error: cannot find root\")\n}\n\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n// Flatten\n\nfunc flattenDescendValue(value interface{}, key string, destination sops.TreeBranch, destinationMap *map[string]bool) (sops.TreeBranch, error) {\n\tswitch value := value.(type) {\n\tcase sops.TreeBranch:\n\t\treturn flattenDescendMap(value, key+mapSeparator, destination, destinationMap)\n\tcase []interface{}:\n\t\treturn flattenDescendArray(value, key+listSeparator, destination, destinationMap)\n\t}\n\tif _, ok := (*destinationMap)[key]; ok {\n\t\treturn nil, fmt.Errorf(\"Found key collision %q while flattening\", key)\n\t}\n\tdestination = append(destination, sops.TreeItem{\n\t\tKey:   key,\n\t\tValue: value,","sourceCodeStart":181,"sourceCodeEnd":217,"githubUrl":"https://github.com/getsops/sops/blob/13442bb98183887d7a9ac09ec8ab0564673a59d8/stores/flatten.go#L181-L217","documentation":"unflattenTreeBranch asserts that the reconstructed root of the nested tree is a sops.TreeBranch (a map). This is a defensive internal invariant check: if convert() returned something that is not a TreeBranch, the flattening logic produced an unexpected shape and the function cannot return a valid TreeBranch.","triggerScenarios":"Practically unreachable in normal use because convert() returns sops.TreeBranch for a root with subkeys and TreeBranch{} for an empty root; it can only surface if convert's internal logic changes or a nil/degenerate node tree reaches the type assertion, i.e. a genuine bug in the stores package.","commonSituations":"Seen only when hacking on sops itself — modifying convert() or place() so the root node ends up holding only a scalar value or only list indices — or when bisecting an unexpected regression in the flatten/unflatten code.","solutions":["Report/fix as a bug: inspect whether convert() returned a []interface{} (list-only root) or scalar and correct the node construction","Check that at least one mapToken path exists in the flattened keys so the root builds subkeys","Verify you are on an unmodified, released version of github.com/getsops/sops/v3/stores"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":"if tb, ok := result.(sops.TreeBranch); ok {\n\t// safe to use tb\n}","tryCatchPattern":"tb, err := unflattenTreeBranch(branch)\nif err != nil {\n\tif err.Error() == \"Internal error: cannot find root\" {\n\t\treturn fmt.Errorf(\"internal sops bug, please report: %w\", err)\n\t}\n\treturn err\n}","preventionTips":["Treat this as a library bug: file an issue with a reproducing branch","Pin released versions of sops/v3","Avoid forking/modifying stores/flatten.go internals"],"tags":["go","sops","internal-error","type-assertion"],"backgroundTag":"internal-invariant-violation","analyzedSha":"13442bb98183887d7a9ac09ec8ab0564673a59d8","analyzedAt":"2026-09-01T03:53:00.447Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}