sipeed/picoclaw · error
model_name is required
Error message
model_name is required
What it means
Returned by POST /api/models/default (handleSetDefaultModel) when the JSON body parses but contains no non-empty model_name field. The handler unmarshals into an anonymous struct with a single ModelName field; any body that leaves it as the zero value (""), including an empty object or a body with a wrong key, is rejected with 400 before any config is loaded. This is a request-shape guard, not a model-existence check.
Source
Thrown at web/backend/api/models.go:551
// POST /api/models/default
func (h *Handler) handleSetDefaultModel(w http.ResponseWriter, r *http.Request) {
body, err := io.ReadAll(io.LimitReader(r.Body, 1<<20))
if err != nil {
http.Error(w, "Failed to read request body", http.StatusBadRequest)
return
}
defer r.Body.Close()
var req struct {
ModelName string `json:"model_name"`
}
if err = json.Unmarshal(body, &req); err != nil {
http.Error(w, fmt.Sprintf("Invalid JSON: %v", err), http.StatusBadRequest)
return
}
if req.ModelName == "" {
http.Error(w, "model_name is required", http.StatusBadRequest)
return
}
cfg, err := config.LoadConfig(h.configPath)
if err != nil {
http.Error(w, fmt.Sprintf("Failed to load config: %v", err), http.StatusInternalServerError)
return
}
// Verify the model_name exists in model_list and is not a virtual model
found := false
isVirtual := false
for _, m := range cfg.ModelList {
if m.ModelName == req.ModelName {
found = true
isVirtual = m.IsVirtual()
break
}View on GitHub (pinned to 49183d7e8d)
Solutions
- Send {"model_name": "<name>"} with Content-Type: application/json and verify the key is exactly model_name
- Check the client object for undefined/null before serializing (e.g. if (!name) throw)
- GET /api/models first and populate the picker from real model_name values so an empty submit is impossible
Example fix
// before
await fetch('/api/models/default', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({ model: selectedName }),
});
// after
await fetch('/api/models/default', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({ model_name: selectedName }),
}); Defensive patterns
Strategy: validation
Validate before calling
function assertSetDefaultPayload(body: unknown): { model_name: string } {
if (typeof body !== 'object' || body === null) throw new Error('body must be an object');
const name = (body as any).model_name;
if (typeof name !== 'string' || name.trim() === '') throw new Error('model_name is required');
return { model_name: name };
}
// before sending:
const payload = assertSetDefaultPayload({ model_name: selected });
await fetch('/api/models/default', { method: 'POST', headers: {'Content-Type':'application/json'}, body: JSON.stringify(payload) }); Type guard
function isSetDefaultModelBody(v: unknown): v is { model_name: string } {
return typeof v === 'object' && v !== null
&& typeof (v as any).model_name === 'string'
&& (v as any).model_name.length > 0;
} Try / catch
try {
const res = await fetch('/api/models/default', {...});
if (res.status === 400) { /* show 'model_name is required' next to the picker */ }
} catch (e) { /* network-level only */ } Prevention
- Bind the default-model picker to real model_name values from GET /api/models and disable submit while empty
- Name the field model_name everywhere — add a lint/ESLint rule or shared type for the request payload
- Unit-test the client payload shape against the API contract in CI
When it happens
Trigger: POST /api/models/default with body {}, {"model_name": ""}, or {"model": "gpt-4o"} (wrong field name). Also hit when a client omits Content-Type: application/json and sends a form-encoded body the JSON decoder maps to nothing.
Common situations: Frontend sends a stale field name after an API rename (model vs model_name); a dropdown bound to an empty selection submits an empty string; JSON.stringify of an object whose property was undefined; curl calls missing the -d body entirely.
Related errors
- Invalid JSON
- Failed to save config
- Failed to encode response
- Invalid JSON: %v
- Cannot set virtual model %q as default
AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15).
Data as JSON: /api/errors/6c825c75fd1e3ebf.
Report an issue: GitHub.