{"record":{"id":"b5838e33473e8991","repo":"googleapis/mcp-toolbox","slug":"doc-d-unexpected-non-string-key-in-input-v","errorCode":null,"errorMessage":"doc %d: unexpected non-string key in input: %v","messagePattern":"doc (.+?): unexpected non-string key in input: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/internal/config.go","lineNumber":247,"sourceCode":"\t// convert configuration file to flat format\n\tvar input yaml.MapSlice\n\tdecoder := yaml.NewDecoder(bytes.NewReader(raw), yaml.UseOrderedMap())\n\tencoder := yaml.NewEncoder(&buf, yaml.UseLiteralStyleIfMultiline(true))\n\n\tnestedFormatKey := []string{\"sources\", \"authServices\", \"embeddingModels\", \"tools\", \"toolsets\", \"prompts\", \"groups\"}\n\tdocIndex := 0\n\tfor {\n\t\tif err := decoder.Decode(&input); err != nil {\n\t\t\tif err == io.EOF {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\treturn nil, err\n\t\t}\n\t\tdocIndex++\n\t\tfor _, item := range input {\n\t\t\tkey, ok := item.Key.(string)\n\t\t\tif !ok {\n\t\t\t\treturn nil, fmt.Errorf(\"doc %d: unexpected non-string key in input: %v\", docIndex, item.Key)\n\t\t\t}\n\t\t\tif hasKindField(input) {\n\t\t\t\t// this doc is already in flat format, encode to buf\n\t\t\t\tif err := encoder.Encode(migrateToolsetKind(ctx, input)); err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\t\t\t// check if value conversion to yaml.MapSlice successfully\n\t\t\tif slice, ok := item.Value.(yaml.MapSlice); slices.Contains(nestedFormatKey, key) && ok {\n\t\t\t\t// srcKey is kept for error messages, which should name the key the\n\t\t\t\t// user actually wrote rather than the flat kind it maps to.\n\t\t\t\tsrcKey := key\n\t\t\t\tswitch key {\n\t\t\t\tcase \"authServices\":\n\t\t\t\t\tkey = \"authService\"\n\t\t\t\tcase \"sources\":\n\t\t\t\t\tkey = \"source\"","sourceCodeStart":229,"sourceCodeEnd":265,"githubUrl":"https://github.com/googleapis/mcp-toolbox/blob/8cc6e09de2ad7b8bffc77751799585a1401a48eb/cmd/internal/config.go#L229-L265","documentation":"ConvertConfig returns this when a YAML document in the input config stream contains a mapping key that is not a string. Migration expects every key in each document to be a string (section names like 'sources', 'tools'); non-string keys cannot be mapped to the flat schema. The doc index and offending key value are included.","triggerScenarios":"A config file whose YAML has a non-string mapping key, e.g. `123: value`, `true: ...`, or an unquoted key that YAML decodes as int/bool, encountered while iterating input items in ConvertConfig.","commonSituations":"Unquoted numeric or boolean-looking keys in YAML (e.g. `on:`, `no:`, version numbers as keys) — classic YAML Norway problem; machine-generated configs emitting JSON with non-string keys.","solutions":["Quote the offending key so YAML parses it as a string (e.g. \"123\": or \"on\":).","Rename numeric/boolean keys to descriptive string names matching the schema.","Validate the YAML with a linter that flags non-string keys before loading."],"exampleFix":"# before: key parsed as boolean (YAML 1.1)\non:\n  tools: []\n# after\n\"on\":\n  tools: []\n# or better, rename:\nenabled:\n  tools: []","handlingStrategy":"validation","validationCode":"var doc map[string]any\nif err := yaml.Unmarshal(raw, &doc); err != nil { log.Fatal(err) }\nfor k := range doc {\n    if _, ok := k.(string); !ok { log.Fatalf(\"non-string key: %v\", k) }\n}","typeGuard":"func allStringKeys(n yaml.Node) bool {\n    for i := 0; i+1 < len(n.Content); i += 2 {\n        if n.Content[i].Tag != \"!!str\" { return false }\n    }\n    return true\n}","tryCatchPattern":"if strings.Contains(err.Error(), \"unexpected non-string key in input\") {\n    log.Fatalf(\"quote or rename non-string YAML keys: %v\", err)\n}","preventionTips":["Quote any key that YAML might parse as bool/int (on, off, yes, no, 123).","Run yamllint with key-duplicates/quoted-keys rules on config files.","Generate configs from JSON tooling with string-only keys."],"tags":["config","yaml","migration","validation"],"backgroundTag":"yaml-non-string-key","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"}