sipeed/picoclaw · error
Model %q cannot be used as the default chat model
Error message
Model %q cannot be used as the default chat model
What it means
Returned by POST /api/models/default when the model is real and non-virtual but its provider fails defaultModelAllowedForModelConfig, which extracts the provider protocol and checks providers.IsDefaultModelProvider. Only chat-capable providers qualify; utility providers (embedding, TTS, ASR, etc.) are rejected because the default drives agent chat, and a non-chat model would break every new conversation.
Source
Thrown at web/backend/api/models.go:582
for _, m := range cfg.ModelList {
if m.ModelName == req.ModelName {
found = true
isVirtual = m.IsVirtual()
break
}
}
if !found {
http.Error(w, fmt.Sprintf("Model %q not found in model_list", req.ModelName), http.StatusNotFound)
return
}
if isVirtual {
http.Error(w, fmt.Sprintf("Cannot set virtual model %q as default", req.ModelName), http.StatusBadRequest)
return
}
for _, m := range cfg.ModelList {
if m.ModelName == req.ModelName {
if !defaultModelAllowedForModelConfig(m) {
http.Error(
w,
fmt.Sprintf("Model %q cannot be used as the default chat model", req.ModelName),
http.StatusBadRequest,
)
return
}
break
}
}
cfg.Agents.Defaults.ModelName = req.ModelName
if err := config.SaveConfig(h.configPath, cfg); err != nil {
http.Error(w, fmt.Sprintf("Failed to save config: %v", err), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")View on GitHub (pinned to 49183d7e8d)
Solutions
- Choose a model backed by a chat-capable provider (e.g. an OpenAI/Anthropic-compatible LLM) as the default
- List models and pick one whose provider is in the default-eligible set exposed by the models endpoint
- If you believe the provider should qualify, check IsDefaultModelProvider in the providers package and upgrade or patch the allowlist
Example fix
// before const target = models[0]; // e.g. an embedding model // after const target = models.find(m => m.provider === 'openai');
Defensive patterns
Strategy: validation
Validate before calling
const models = await (await fetch('/api/models')).json();
const chatProviders = new Set(['openai', 'anthropic', 'google-antigravity']); // chat-capable providers
const target = models.find((m: any) => chatProviders.has((m.provider || '').toLowerCase()));
if (!target) throw new Error('no default-eligible chat model configured');
await postDefault(target.model_name); Type guard
function isDefaultAllowedProvider(provider: string): boolean {
const chat = new Set(['openai', 'anthropic', 'google-antigravity']);
return chat.has(provider.toLowerCase());
} Try / catch
try {
const res = await fetch('/api/models/default', {...});
if (res.status === 400 && (await res.text()).includes('default chat model')) {
/* restrict picker to chat-capable providers and retry */
}
} catch (e) { /* network */ } Prevention
- Only offer chat-capable LLM providers in the default-model selector
- Keep utility models (embedding/TTS/ASR) visibly separated from chat models in the UI
- When adding a provider, record whether it is default-eligible so the UI can filter
When it happens
Trigger: POST /api/models/default naming a model whose provider is, for example, an embedding or speech provider rather than an LLM chat provider. The model exists and is not virtual, but ExtractProtocol yields a provider outside the default-model allowlist.
Common situations: The config mixes ASR/embedding models into model_list and a script picks the first entry; a user assumes any configured model can be the default; provider renaming moved a chat provider out of the allowlist after an upgrade.
Related errors
- model_name is required
- Cannot set virtual model %q as default
- provider is required
- provider %q does not support model listing
- No default API base for provider %q
AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15).
Data as JSON: /api/errors/45d1cc0ba34aef72.
Report an issue: GitHub.