sipeed/picoclaw · warning
Invalid index
Error message
Invalid index
What it means
HTTP 400 returned by PUT /api/models/{index} (handleUpdateModel) when strconv.Atoi(r.PathValue("index")) fails — the path segment is not a plain base-10 integer. Note the range check happens later: a negative-but-numeric index like -1 parses fine here and instead produces the 404 'Index out of range' error.
Source
Thrown at web/backend/api/models.go:368
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]any{
"status": "ok",
"index": len(cfg.ModelList) - 1,
})
}
// handleUpdateModel replaces a model configuration entry at the given index.
// If the request body omits api_key (or sends an empty string), the existing
// stored key is preserved so callers can update only api_base / proxy without
// exposing or clearing the secret.
//
// PUT /api/models/{index}
func (h *Handler) handleUpdateModel(w http.ResponseWriter, r *http.Request) {
idx, err := strconv.Atoi(r.PathValue("index"))
if err != nil {
http.Error(w, "Invalid index", http.StatusBadRequest)
return
}
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 rawFields map[string]json.RawMessage
if err = json.Unmarshal(body, &rawFields); err != nil {
http.Error(w, fmt.Sprintf("Invalid JSON: %v", err), http.StatusBadRequest)
return
}
type custom struct {
config.ModelConfigView on GitHub (pinned to 49183d7e8d)
Solutions
- Use the numeric position from GET /api/models (the index field of each entry), not the model name
- Verify the value is a non-negative integer before building the URL: Number.isInteger(idx) && idx >= 0
- Template it directly: `/api/models/${idx}` with idx from the list response — never string-concatenate an untrusted variable
- Check for trailing slashes or empty segments in the request path
Example fix
// before: model name or undefined leaks into the URL
await fetch(`/api/models/${selected?.name}`);
// after: validated numeric index from the listing
if (!Number.isInteger(selected?.index) || selected.index < 0) throw new Error('bad index');
await fetch(`/api/models/${selected.index}`, { method: 'PUT', ... }); Defensive patterns
Strategy: validation
Validate before calling
if (!Number.isInteger(idx) || idx < 0) throw new Error(`index must be a non-negative integer, got ${idx}`); Type guard
function isModelIndex(v) {
return Number.isInteger(v) && v >= 0;
} Prevention
- Always template the numeric index into the URL: `/api/models/${idx}`
- Never substitute model_name or undefined into the {index} path slot
- Keep a single source of truth: the index returned by GET /api/models
- Assert the index type right before the fetch call in edit handlers
When it happens
Trigger: PUT /api/models/abc, /api/models/1.5, /api/models/%20, or /api/models/ (empty index from a trailing-slash route), all of which make Atoi return an error.
Common situations: Frontend building the URL with an undefined/null id (becomes 'undefined'); passing a model_name instead of the numeric list position; route typos or extra path segments; URL-encoding artifacts.
Related errors
AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15).
Data as JSON: /api/errors/3a689cbf341464a5.
Report an issue: GitHub.