{"record":{"id":"39d6d579ffd93564","repo":"googleapis/mcp-toolbox","slug":"doc-d-invalid-config-format-at-key-q-expected","errorCode":null,"errorMessage":"doc %d: invalid config format at key %q: expected nested format keys and type map","messagePattern":"doc (.+?): invalid config format at key %q: expected nested format keys and type map","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/internal/config.go","lineNumber":288,"sourceCode":"\t\t\t\tcase \"toolsets\":\n\t\t\t\t\tkey = \"toolset\"\n\t\t\t\tcase \"prompts\":\n\t\t\t\t\tkey = \"prompt\"\n\t\t\t\tcase \"groups\":\n\t\t\t\t\tkey = \"group\"\n\t\t\t\t}\n\t\t\t\ttransformed, err := transformDocs(key, slice)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, fmt.Errorf(\"doc %d: invalid config format at key %q: %w\", docIndex, srcKey, err)\n\t\t\t\t}\n\t\t\t\t// encode per-doc\n\t\t\t\tfor _, doc := range transformed {\n\t\t\t\t\tif err := encoder.Encode(migrateToolsetKind(ctx, doc)); err != nil {\n\t\t\t\t\t\treturn nil, err\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\treturn nil, fmt.Errorf(\"doc %d: invalid config format at key %q: expected nested format keys and type map\", docIndex, key)\n\t\t\t}\n\t\t}\n\t}\n\treturn buf.Bytes(), nil\n}\n\n// hasKindField is a helper function to check if an input is in flat format\nfunc hasKindField(input yaml.MapSlice) bool {\n\tfor _, item := range input {\n\t\tif key, ok := item.Key.(string); ok && key == \"kind\" {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// migrateToolsetKind rewrites `kind: toolset` to `kind: group`, preserving field\n// order, and returns other kinds unchanged. Every flat doc passes through here,","sourceCodeStart":270,"sourceCodeEnd":306,"githubUrl":"https://github.com/googleapis/mcp-toolbox/blob/8cc6e09de2ad7b8bffc77751799585a1401a48eb/cmd/internal/config.go#L270-L306","documentation":"ConvertConfig returns this when a top-level key in a config document is neither in already-flat format nor the expected nested format (a keys-and-type map). Migration only understands two shapes; anything else — a scalar, a bare list at the wrong level, or an unrecognized structure — is rejected. The doc index and offending key are reported.","triggerScenarios":"A config document has a key like `sources:` or `tools:` whose value is not a map of sub-keys with type maps (nested legacy) and not already-flat docs — e.g. `sources: []` or `sources: mydb` encountered in ConvertConfig.","commonSituations":"Typing `sources:` with a list instead of a map; collapsing a section to a scalar; truncating or hand-editing configs; using a config from an incompatible/unrelated schema.","solutions":["Change the key's value to a proper mapping: either the current flat schema or the legacy nested keys-and-type map.","Check that the section (sources/tools/etc.) is a map whose entries contain a 'kind' and parameters.","Regenerate the config from the current toolbox docs/templates instead of editing a broken file.","Use the migration command on the original legacy config to produce a valid flat file."],"exampleFix":"# before\nsources:\n  - mydb\n# after\nsources:\n  mydb:\n    kind: postgres\n    host: localhost\n    port: 5432\n    database: appdb\n    user: ${DB_USER}\n    password: ${DB_PASSWORD}","handlingStrategy":"validation","validationCode":"var doc map[string]yaml.Node\nif err := node.Decode(&doc); err != nil { log.Fatal(err) }\nfor key, val := range doc {\n    if val.Kind != yaml.MappingNode { log.Fatalf(\"key %q must map to a section map\", key) }\n}","typeGuard":"func isSectionMap(n *yaml.Node) bool {\n    return n != nil && n.Kind == yaml.MappingNode\n}","tryCatchPattern":"if strings.Contains(err.Error(), \"expected nested format keys and type map\") {\n    log.Fatalf(\"section must be a map (legacy nested or flat format): %v\", err)\n}","preventionTips":["Ensure each top-level section (sources, tools, prompts, groups) is a YAML mapping, never a scalar or bare list.","Validate section shapes with a schema check in CI.","Regenerate configs from current templates rather than editing unknown-format files."],"tags":["config","migration","yaml","validation","schema"],"backgroundTag":"config-format-migration-failed","analyzedSha":"8cc6e09de2ad7b8bffc77751799585a1401a48eb","analyzedAt":"2026-09-05T01:10:36.887Z","contentChangedAt":"2026-09-05T01:10:36.887Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}