alibaba/open-code-review · error

invalid model list for %s: %w

Error message

invalid model list for %s: %w

What it means

The provider-level models field is parsed by parseModelListValue; if the value cannot be parsed into a valid model list, applyProviderField wraps the failure as "invalid model list for <key>: %w" with the full dotted key.

Source

Thrown at cmd/opencodereview/config_cmd.go:644

		if err := llm.ValidateProtocol(normalized); err != nil {
			return err
		}
		entry.Protocol = normalized
		// Switching away from bedrock leaves aws_region/aws_profile as dead
		// config that reads as applied but nothing reads it — clear both, the
		// same way the TUI drops url/api_key/auth_header when switching onto
		// bedrock (see cpAmbientProtocol in provider_tui.go).
		if normalized != llm.ProtocolAnthropicBedrock && (entry.AWSRegion != "" || entry.AWSProfile != "") {
			fmt.Fprintf(os.Stderr, "[ocr] WARNING: clearing aws_region/aws_profile on %q: protocol %q does not use the AWS credential chain\n", providerName, normalized)
			entry.AWSRegion = ""
			entry.AWSProfile = ""
		}
	case "model":
		entry.Model = value
	case "models":
		models, err := parseModelListValue(value)
		if err != nil {
			return fmt.Errorf("invalid model list for %s: %w", key, err)
		}
		entry.Models = models
	case "auth_header":
		normalized, err := llm.NormalizeAuthHeader(value)
		if err != nil {
			return err
		}
		entry.AuthHeader = normalized
	case "extra_body":
		var m map[string]any
		if err := json.Unmarshal([]byte(value), &m); err != nil {
			return fmt.Errorf("invalid JSON for %s: %w", key, err)
		}
		entry.ExtraBody = m
	case "extra_headers":
		parsed, err := llm.ParseExtraHeaders(value)
		if err != nil {
			return fmt.Errorf("invalid extra headers for %s: %w", key, err)

View on GitHub (pinned to 5cf97d0d15)

Solutions

  1. Check parseModelListValue's expected format (comma-separated names vs JSON array) and reformat the value
  2. Provide at least one model name; an empty value produces no valid list
  3. Quote the value so shell word-splitting doesn't break it: `ocr config set providers.x.models "m1,m2"`
  4. Set a single default with the `model` field instead if you don't need a list

Example fix

// before
ocr config set providers.openai.models ""
// after
ocr config set providers.openai.models "gpt-4o,gpt-4o-mini"
Defensive patterns

Strategy: validation

Validate before calling

models := strings.Split(value, ",")
for i, m := range models {
    models[i] = strings.TrimSpace(m)
}
if len(models) == 0 || (len(models) == 1 && models[0] == "") {
    return errors.New("models needs at least one model name")
}
_ = runConfigSet("providers.openai.models", strings.Join(models, ","))

Try / catch

if err := runConfigSet("providers.openai.models", v); err != nil {
    if strings.Contains(err.Error(), "invalid model list for") {
        fmt.Fprintf(os.Stderr, "%q is not a valid model list; supply at least one model name\n", v)
    }
}

Prevention

When it happens

Trigger: `ocr config set providers.<name>.models <value>` (or custom_providers path) with an empty list, malformed separators, or a structure parseModelListValue rejects.

Common situations: Passing comma-separated names where a JSON array is expected (or vice versa); quoting mistakes eating the separators; an empty string from an unset shell variable; switching providers and pasting the wrong list format.

Related errors


AI-assisted analysis of alibaba/open-code-review@5cf97d0d15 (2026-09-02). Data as JSON: /api/errors/2d972aa8a9d09f7f. Report an issue: GitHub.