sipeed/picoclaw · error
Invalid JSON
Error message
Invalid JSON
What it means
Returned by POST /api/models/test-inline when json.Unmarshal of the body into {provider, model, api_base, api_key, auth_method, model_index} fails. Unlike sibling handlers, this error message omits the %v detail, so you must validate the JSON client-side to find the cause. Expected shape: one JSON object; model_index must be a number when present.
Source
Thrown at web/backend/api/models.go:997
//
// POST /api/models/test-inline
func (h *Handler) handleTestInlineModel(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
}
var req struct {
Provider string `json:"provider"`
Model string `json:"model"`
APIBase string `json:"api_base"`
APIKey string `json:"api_key"`
AuthMethod string `json:"auth_method"`
ModelIndex *int `json:"model_index"`
}
if err := json.Unmarshal(body, &req); err != nil {
http.Error(w, "Invalid JSON", http.StatusBadRequest)
return
}
m := &config.ModelConfig{
Provider: strings.TrimSpace(req.Provider),
Model: strings.TrimSpace(req.Model),
APIBase: strings.TrimSpace(req.APIBase),
AuthMethod: strings.TrimSpace(req.AuthMethod),
}
if req.APIKey != "" {
m.SetAPIKey(req.APIKey)
}
// When api_key is empty and model_index is provided, fall back to stored credentials.
// This lets the edit form test unsaved field changes while using the saved key.
// Only reuse the stored key when the provider and effective API base match
// the saved model, to prevent attaching a credential to a different endpoint.
if req.APIKey == "" && req.ModelIndex != nil {View on GitHub (pinned to 49183d7e8d)
Solutions
- Validate with JSON.parse on the client before sending — the server message has no detail to help you
- Send exactly: {provider, model, api_base, api_key, auth_method, model_index} with model_index as a number
- Ensure Content-Type: application/json and a single JSON.stringify call
Example fix
// before
body: rawJsonString // previously built via template literal
// after
body: JSON.stringify({
provider: 'openai',
model: 'gpt-4o',
api_base: 'https://api.openai.com/v1',
api_key: key,
model_index: 0,
}) Defensive patterns
Strategy: validation
Validate before calling
function buildTestInlineBody(p: { provider: string; model: string; api_base?: string; api_key?: string; auth_method?: string; model_index?: number }): string {
if (typeof p.provider !== 'string' || typeof p.model !== 'string') throw new Error('provider and model are required strings');
if (p.model_index !== undefined && !Number.isInteger(p.model_index)) throw new Error('model_index must be an integer');
return JSON.stringify(p);
} Type guard
function isTestInlinePayload(v: unknown): v is { provider: string; model: string; api_base?: string; api_key?: string; auth_method?: string; model_index?: number } {
if (typeof v !== 'object' || v === null) return false;
const o = v as Record<string, unknown>;
return typeof o.provider === 'string' && typeof o.model === 'string'
&& (o.model_index === undefined || typeof o.model_index === 'number');
} Try / catch
try {
const res = await fetch('/api/models/test-inline', {...});
if (res.status === 400 && (await res.text()) === 'Invalid JSON') {
/* server gives no detail — run JSON.parse(body) locally to locate the defect */
}
} catch (e) { /* network */ } Prevention
- Since this endpoint omits error detail, validate with JSON.parse round-trip on the client
- Use the exact field names: provider, model, api_base, api_key, auth_method, model_index
- model_index must be a JSON number when present
When it happens
Trigger: POST /api/models/test-inline with unquoted keys, an array body, {"model_index": "2"} (string vs *int), double-stringified JSON, or trailing garbage after the object.
Common situations: Reusing a fetch wrapper that JSON.stringify's an already-serialized string; sending FormData without conversion; template-built JSON with a trailing comma; field renamed on the client (model_name vs model).
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- model_name is required
- Failed to save config
- Failed to encode response
- Invalid JSON: %v
- provider is required
AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15).
Data as JSON: /api/errors/528a285dee5b5528.
Report an issue: GitHub.