sipeed/picoclaw · error
model_name is required: %#v
Error message
model_name is required: %#v
What it means
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.
Source
Thrown at pkg/config/migration.go:515
func mergeModelListsWithMap(mainML []any, secML map[string]any) error {
// Build indexed keys like toNameIndex does
indexedKeys := make(map[string]int)
countMap := make(map[string]int)
for i, m := range mainML {
if mVal, ok := m.(map[string]any); ok {
if name, hasName := mVal["model_name"]; hasName {
nameStr, ok := name.(string)
if !ok {
return fmt.Errorf("model_name must be a string, got %T", name)
}
index := countMap[nameStr]
indexedKeys[fmt.Sprintf("%s:%d", nameStr, index)] = i
if _, ok := indexedKeys[nameStr]; !ok {
indexedKeys[nameStr] = i
}
countMap[nameStr]++
} else {
return fmt.Errorf("model_name is required: %#v", mVal)
}
}
}
for k, v := range secML {
if i, ok := indexedKeys[k]; ok {
if vv, ok := v.(map[string]any); ok {
if mVal, ok := mainML[i].(map[string]any); ok {
mVal["api_keys"] = vv["api_keys"]
}
}
} else {
logger.Warnf("model_name not found in main config: %s", k)
}
delete(secML, k)
}
return nilView on GitHub (pinned to 49183d7e8d)
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)
Example fix
# before
model_list:
- provider: openai
api_key: sk-...
# after
model_list:
- model_name: gpt-4o
provider: openai
api_key: sk-... Defensive patterns
Strategy: validation
Validate before calling
// Require model_name on every array-style entry before merge.
func validateModelListKeys(ml []any) error {
for i, m := range ml {
entry, ok := m.(map[string]any)
if !ok { continue }
if _, has := entry["model_name"]; !has {
return fmt.Errorf("model_list[%d] (%v): model_name is required", i, entry)
}
}
return nil
} Type guard
func hasModelName(m any) bool {
entry, ok := m.(map[string]any)
if !ok { return false }
_, has := entry["model_name"]
return has
} Try / catch
if err := mergeModelListsWithMap(mainML, secML); err != nil {
// %#v in the message shows the offending entry — use it to locate the line in the YAML.
log.Printf("migration failed on entry: %v", err)
return err
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- model_name must be a string, got %T
- failed to parse security config %s: %w
- failed to parse legacy skills security config: %w
- invalid WeCom QR generate URL: %w
- invalid WeCom QR query URL: %w
AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15).
Data as JSON: /api/errors/8e50c7a7538fc2b8.
Report an issue: GitHub.