{"record":{"id":"50d6e050e115c0a6","repo":"ipfs/kubo","slug":"s-key-is-not-a-map","errorCode":null,"errorMessage":"%s key is not a map","messagePattern":"(.+?) key is not a map","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"config/config.go","lineNumber":247,"sourceCode":"func CheckKey(key string) error {\n\tconf := Config{}\n\n\t// Convert an empty config to a map without JSON.\n\tcursor := ReflectToMap(&conf)\n\n\t// Parse the key and verify it's presence in the map.\n\tvar ok bool\n\tvar mapCursor map[string]any\n\n\tparts := strings.Split(key, \".\")\n\tfor i, part := range parts {\n\t\tmapCursor, ok = cursor.(map[string]any)\n\t\tif !ok {\n\t\t\tif cursor == nil {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\tpath := strings.Join(parts[:i], \".\")\n\t\t\treturn fmt.Errorf(\"%s key is not a map\", path)\n\t\t}\n\n\t\tcursor, ok = mapCursor[part]\n\t\tif !ok {\n\t\t\t// If the config sections is a map, validate against the default entry.\n\t\t\tif cursor, ok = mapCursor[\"*\"]; ok {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tpath := strings.Join(parts[:i+1], \".\")\n\t\t\treturn fmt.Errorf(\"%s not found\", path)\n\t\t}\n\t}\n\treturn nil\n}\n","sourceCodeStart":229,"sourceCodeEnd":262,"githubUrl":"https://github.com/ipfs/kubo/blob/329838acdfafae224582930457efe80aa217afc0/config/config.go#L229-L262","documentation":"CheckKey() walks a dotted config path (e.g. \"Addresses.API\") through nested maps in the config structure. If an intermediate segment resolves to a value that is not a map (and not nil), the path cannot be descended further and this error names the deepest valid prefix of the path.","triggerScenarios":"Calling CheckKey or SetConfigKey with a dotted key where an intermediate segment names a scalar value, e.g. \"Addresses.API.Sub\" when Addresses.API is a string.","commonSituations":"Typo in the key path causing traversal into a leaf value; config schema change making a formerly-nested section scalar; automation scripts building paths dynamically from bad input.","solutions":["Correct the dotted path so each prefix names a config section (map), not a leaf value","Print/inspect the config (ipfs config) to verify the actual nesting at the reported prefix","Stop the path at the reported prefix and set the leaf value directly instead"],"exampleFix":"// before\nerr := SetConfigKey(cfg, \"Addresses.API.extra\", val) // Addresses.API is a string\n// after\nerr := SetConfigKey(cfg, \"Addresses.API\", val)","handlingStrategy":"validation","validationCode":"// Verify each dotted prefix names an existing section before descending\nfunc pathIsSection(cfg *config.Config, dotted string) bool {\n\tcur := any(cfg)\n\tfor _, part := range strings.Split(dotted, \".\") {\n\t\tm, ok := cur.(map[string]any)\n\t\tif !ok {\n\t\t\treturn false\n\t\t}\n\t\tcur, ok = m[part]\n\t\tif !ok {\n\t\t\treturn false\n\t\t}\n\t}\n\t_, isMap := cur.(map[string]any)\n\treturn isMap\n}","typeGuard":"func isSection(v any) bool {\n\t_, ok := v.(map[string]any)\n\treturn ok\n}","tryCatchPattern":"if err := config.CheckKey(cfg, key); err != nil {\n\tif strings.Contains(err.Error(), \"key is not a map\") {\n\t\t// path crosses a leaf value: correct the key or write the leaf directly\n\t\treturn fmt.Errorf(\"invalid config path %q: %w\", key, err)\n\t}\n\treturn err\n}","preventionTips":["Validate dotted keys with `ipfs config show` structure before automating writes","Never append extra segments to a key that already names a leaf value","Keep a constant list of valid key paths in scripts instead of building them dynamically"],"tags":["config","validation","path"],"backgroundTag":"config-key-not-a-map","analyzedSha":"329838acdfafae224582930457efe80aa217afc0","analyzedAt":"2026-09-03T18:30:52.135Z","contentChangedAt":"2026-09-03T18:30:52.135Z","schemaVersion":2},"datasetVersion":"2026-09-11T00:17:11.886Z"}