{"record":{"id":"8e50c7a7538fc2b8","repo":"sipeed/picoclaw","slug":"model-name-is-required-v","errorCode":null,"errorMessage":"model_name is required: %#v","messagePattern":"model_name is required: %#v","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/config/migration.go","lineNumber":515,"sourceCode":"func mergeModelListsWithMap(mainML []any, secML map[string]any) error {\n\t// Build indexed keys like toNameIndex does\n\tindexedKeys := make(map[string]int)\n\tcountMap := make(map[string]int)\n\tfor i, m := range mainML {\n\t\tif mVal, ok := m.(map[string]any); ok {\n\t\t\tif name, hasName := mVal[\"model_name\"]; hasName {\n\t\t\t\tnameStr, ok := name.(string)\n\t\t\t\tif !ok {\n\t\t\t\t\treturn fmt.Errorf(\"model_name must be a string, got %T\", name)\n\t\t\t\t}\n\t\t\t\tindex := countMap[nameStr]\n\t\t\t\tindexedKeys[fmt.Sprintf(\"%s:%d\", nameStr, index)] = i\n\t\t\t\tif _, ok := indexedKeys[nameStr]; !ok {\n\t\t\t\t\tindexedKeys[nameStr] = i\n\t\t\t\t}\n\t\t\t\tcountMap[nameStr]++\n\t\t\t} else {\n\t\t\t\treturn fmt.Errorf(\"model_name is required: %#v\", mVal)\n\t\t\t}\n\t\t}\n\t}\n\n\tfor k, v := range secML {\n\t\tif i, ok := indexedKeys[k]; ok {\n\t\t\tif vv, ok := v.(map[string]any); ok {\n\t\t\t\tif mVal, ok := mainML[i].(map[string]any); ok {\n\t\t\t\t\tmVal[\"api_keys\"] = vv[\"api_keys\"]\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tlogger.Warnf(\"model_name not found in main config: %s\", k)\n\t\t}\n\t\tdelete(secML, k)\n\t}\n\n\treturn nil","sourceCodeStart":497,"sourceCodeEnd":533,"githubUrl":"https://github.com/sipeed/picoclaw/blob/49183d7e8daed0dba89ddbb6fcb60089401d9680/pkg/config/migration.go#L497-L533","documentation":"Thrown by mergeModelListsWithMap when an array-style model_list entry is a map that has no model_name key at all. model_name is mandatory because the merge builds indexed keys (\"name\", \"name:0\", \"name:1\") from it to locate the matching security entries; without it the entry cannot be keyed, so the merge aborts and prints the whole offending map via %#v.","triggerScenarios":"A model_list entry like `- provider: openai` or `- api_keys: [...]` that omits model_name. Any map entry lacking the key hits the else branch and the entire map is dumped in the error message.","commonSituations":"Renamed field (e.g. `name:` or `model:` instead of `model_name:`), truncated entries from hand-editing, or tooling that emits entries with only provider/credential fields. Appears during config migration when merging main config with a map-style security model_list.","solutions":["Add a model_name string to every entry shown in the %#v dump in the error message","If the field was misnamed (e.g. `name:`), rename it to model_name","Validate the whole list for missing keys before re-running (see validationCode in defense)"],"exampleFix":"# before\nmodel_list:\n  - provider: openai\n    api_key: sk-...\n\n# after\nmodel_list:\n  - model_name: gpt-4o\n    provider: openai\n    api_key: sk-...","handlingStrategy":"validation","validationCode":"// Require model_name on every array-style entry before merge.\nfunc validateModelListKeys(ml []any) error {\n\tfor i, m := range ml {\n\t\tentry, ok := m.(map[string]any)\n\t\tif !ok { continue }\n\t\tif _, has := entry[\"model_name\"]; !has {\n\t\t\treturn fmt.Errorf(\"model_list[%d] (%v): model_name is required\", i, entry)\n\t\t}\n\t}\n\treturn nil\n}","typeGuard":"func hasModelName(m any) bool {\n\tentry, ok := m.(map[string]any)\n\tif !ok { return false }\n\t_, has := entry[\"model_name\"]\n\treturn has\n}","tryCatchPattern":"if err := mergeModelListsWithMap(mainML, secML); err != nil {\n\t// %#v in the message shows the offending entry — use it to locate the line in the YAML.\n\tlog.Printf(\"migration failed on entry: %v\", err)\n\treturn err\n}","preventionTips":["Treat model_name as mandatory in any template/generator that emits model_list","Add a YAML schema (e.g. cue/jsonschema) check to config CI","Watch for renamed variants (name:, model:) when porting configs from other tools"],"tags":["go","config","yaml","validation","migration"],"backgroundTag":null,"analyzedSha":"49183d7e8daed0dba89ddbb6fcb60089401d9680","analyzedAt":"2026-08-15T21:55:41.315Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}