{"record":{"id":"99f69f96063e54f9","repo":"hyperledger/fabric","slug":"missing-group-at-path-s","errorCode":null,"errorMessage":"missing group at path: %s","messagePattern":"missing group at path: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"common/configtx/configmap.go","lineNumber":116,"sourceCode":"\t}\n\n\treturn nil\n}\n\n// configMapToConfig is intended to be called from outside this file\n// It takes a configMap and converts it back into a *cb.ConfigGroup structure\nfunc configMapToConfig(configMap map[string]comparable, rootGroupKey string) (*cb.ConfigGroup, error) {\n\trootPath := pathSeparator + rootGroupKey\n\treturn recurseConfigMap(rootPath, configMap)\n}\n\n// recurseConfigMap is used only internally by configMapToConfig\n// Note, this function no longer mutates the cb.Config* entries within configMap\nfunc recurseConfigMap(path string, configMap map[string]comparable) (*cb.ConfigGroup, error) {\n\tgroupPath := groupPrefix + path\n\tgroup, ok := configMap[groupPath]\n\tif !ok {\n\t\treturn nil, errors.Errorf(\"missing group at path: %s\", groupPath)\n\t}\n\n\tif group.ConfigGroup == nil {\n\t\treturn nil, errors.Errorf(\"ConfigGroup not found at group path: %s\", groupPath)\n\t}\n\n\tnewConfigGroup := protoutil.NewConfigGroup()\n\tproto.Merge(newConfigGroup, group.ConfigGroup)\n\n\tfor key := range group.Groups {\n\t\tupdatedGroup, err := recurseConfigMap(path+pathSeparator+key, configMap)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tnewConfigGroup.Groups[key] = updatedGroup\n\t}\n\n\tfor key := range group.Values {","sourceCodeStart":98,"sourceCodeEnd":134,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/common/configtx/configmap.go#L98-L134","documentation":"configMapToConfig flattens a cb.ConfigGroup tree into a map keyed by path (e.g. 'groups/Application/groups/MSPs') and recurseConfigMap walks it back into a tree. This error means the walk expected a group entry at the given path but the map had none. It indicates the config map was built incompletely — the comparator (NewComparableConfig) always inserts every group, so this usually implies a corrupted or hand-modified map.","triggerScenarios":"recurseConfigMap (via configMapToConfig) iterating a group's Groups when the corresponding 'groups/<path>' entry is absent from the configMap — e.g. a configMap built outside NewComparableConfig or mutated concurrently, since recursion also calls itself for child groups.","commonSituations":"Tests or tools constructing configMap by hand and omitting child group entries; callers passing a different map than the one produced for the same root group; concurrent map modification during conversion.","solutions":["Build the configMap with configtx.NewComparableConfig(group) instead of manually populating it, so every group path is present.","Inspect the reported path in the message and add the missing group entry at that path.","Ensure the root group passed to configMapToConfig is the same one the map was derived from (no mismatched pairing).","Avoid concurrent mutation of the configMap while configMapToConfig runs."],"exampleFix":"// before\nconfigMap := map[string]comparable{}\nconfigMap[\"groups/Application\"] = comparable{ConfigGroup: appGroup}\nconfig := configMapToConfig(configMap) // children missing\n// after\nconfigMap := NewComparableConfig(rootGroup) // full tree flattened\nconfig, err := configMapToConfig(configMap)","handlingStrategy":"validation","validationCode":"import \"strings\"\n\nfunc hasGroupEntry(configMap map[string]configtx.Comparable, path string) bool {\n\t_, ok := configMap[\"groups/\"+path]\n\treturn ok\n}\nif !hasGroupEntry(configMap, \"Application\") {\n\treturn errors.New(\"configMap lacks group entry for Application\")\n}","typeGuard":null,"tryCatchPattern":"// errors are returned, not panicked\nconfig, err := configtx.ConfigMapToConfig(configMap)\nif err != nil {\n\treturn fmt.Errorf(\"config map conversion failed at %q: %w\", reportedPath, err)\n}","preventionTips":["Always build configMap with configtx.NewComparableConfig, never by hand","Keep the map and the root group you pass to configMapToConfig in 1:1 correspondence","Never mutate the configMap while conversion is running","Parse the path embedded in the error message to locate the missing entry"],"tags":["hyperledger-fabric","configtx","config-map"],"backgroundTag":"missing-config-group-path","analyzedSha":"2736b63f8fd5932511d56fe68b7039d15977f7f6","analyzedAt":"2026-09-04T08:52:36.465Z","contentChangedAt":"2026-09-04T08:52:36.465Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}