googleapis/mcp-toolbox · error
doc %d: invalid config format at key %q: expected nested for
Error message
doc %d: invalid config format at key %q: expected nested format keys and type map
What it means
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.
Source
Thrown at cmd/internal/config.go:288
case "toolsets":
key = "toolset"
case "prompts":
key = "prompt"
case "groups":
key = "group"
}
transformed, err := transformDocs(key, slice)
if err != nil {
return nil, fmt.Errorf("doc %d: invalid config format at key %q: %w", docIndex, srcKey, err)
}
// encode per-doc
for _, doc := range transformed {
if err := encoder.Encode(migrateToolsetKind(ctx, doc)); err != nil {
return nil, err
}
}
} else {
return nil, fmt.Errorf("doc %d: invalid config format at key %q: expected nested format keys and type map", docIndex, key)
}
}
}
return buf.Bytes(), nil
}
// hasKindField is a helper function to check if an input is in flat format
func hasKindField(input yaml.MapSlice) bool {
for _, item := range input {
if key, ok := item.Key.(string); ok && key == "kind" {
return true
}
}
return false
}
// migrateToolsetKind rewrites `kind: toolset` to `kind: group`, preserving field
// order, and returns other kinds unchanged. Every flat doc passes through here,View on GitHub (pinned to 8cc6e09de2)
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.
Example fix
# before
sources:
- mydb
# after
sources:
mydb:
kind: postgres
host: localhost
port: 5432
database: appdb
user: ${DB_USER}
password: ${DB_PASSWORD} Defensive patterns
Strategy: validation
Validate before calling
var doc map[string]yaml.Node
if err := node.Decode(&doc); err != nil { log.Fatal(err) }
for key, val := range doc {
if val.Kind != yaml.MappingNode { log.Fatalf("key %q must map to a section map", key) }
} Type guard
func isSectionMap(n *yaml.Node) bool {
return n != nil && n.Kind == yaml.MappingNode
} Try / catch
if strings.Contains(err.Error(), "expected nested format keys and type map") {
log.Fatalf("section must be a map (legacy nested or flat format): %v", err)
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- doc %d: unexpected non-string key in input: %v
- doc %d: invalid config format at key %q: %w
- %s missing 'kind' field or it is not a string
- missing 'kind' field or it is not a string: %v
- %s missing 'name' field or it is not a string
AI-assisted analysis of googleapis/mcp-toolbox@8cc6e09de2 (2026-09-05).
Data as JSON: /api/errors/39d6d579ffd93564.
Report an issue: GitHub.