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.ModelConfig

View on GitHub (pinned to 49183d7e8d)

Solutions

  1. Use the numeric position from GET /api/models (the index field of each entry), not the model name
  2. Verify the value is a non-negative integer before building the URL: Number.isInteger(idx) && idx >= 0
  3. Template it directly: `/api/models/${idx}` with idx from the list response — never string-concatenate an untrusted variable
  4. 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

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.