sipeed/picoclaw · warning
Invalid JSON: %v
Error message
Invalid JSON: %v
What it means
Returned (HTTP 400) by PUT /api/system/autostart in web/backend/api/startup.go:57-59 when json.NewDecoder(r.Body).Decode(&req) fails. The handler decodes the request body into autoStartRequest, a struct with a single boolean field `enabled`; any byte stream that is not a valid JSON object with a boolean-compatible `enabled` value is rejected. The handler does not check Content-Type, so even a form-encoded or text body reaches the decoder and fails. The %v part carries Go's encoding/json error detail (e.g. EOF, invalid character, cannot unmarshal string into bool).
Source
Thrown at web/backend/api/startup.go:58
enabled, supported, message, err := h.getAutoStartStatus()
if err != nil {
http.Error(w, fmt.Sprintf("Failed to read startup setting: %v", err), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(autoStartResponse{
Enabled: enabled,
Supported: supported,
Platform: runtime.GOOS,
Message: message,
})
}
func (h *Handler) handleSetAutoStart(w http.ResponseWriter, r *http.Request) {
var req autoStartRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, fmt.Sprintf("Invalid JSON: %v", err), http.StatusBadRequest)
return
}
if err := h.setAutoStart(req.Enabled); err != nil {
if errors.Is(err, errAutoStartUnsupported) {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
http.Error(w, fmt.Sprintf("Failed to update startup setting: %v", err), http.StatusInternalServerError)
return
}
enabled, supported, message, err := h.getAutoStartStatus()
if err != nil {
http.Error(w, fmt.Sprintf("Failed to verify startup setting: %v", err), http.StatusInternalServerError)
return
}
View on GitHub (pinned to 49183d7e8d)
Solutions
- Send a JSON object with a boolean: curl -X PUT -H 'Content-Type: application/json' -d '{"enabled": true}' http://host/api/system/autostart
- Ensure the value is a real boolean, not the string "true" — coerce with typeof check before fetch
- Set Content-Type: application/json and confirm the body is not empty or double-encoded
- If proxying, verify the request body survives the hop (no body-stripping redirects such as 307/308 mishandling)
Example fix
// before
await fetch('/api/system/autostart', { method: 'PUT', body: 'enabled=true' });
// after
await fetch('/api/system/autostart', {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ enabled: true }),
}); Defensive patterns
Strategy: validation
Validate before calling
// Run before PUT /api/system/autostart
function assertAutoStartPayload(body: unknown): { enabled: boolean } {
if (typeof body !== 'object' || body === null || Array.isArray(body)) throw new TypeError('body must be an object');
const { enabled } = body as { enabled?: unknown };
if (typeof enabled !== 'boolean') throw new TypeError('enabled must be a boolean');
return { enabled };
}
await fetch('/api/system/autostart', {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(assertAutoStartPayload(state)),
}); Type guard
const isAutoStartRequest = (v: unknown): v is { enabled: boolean } =>
typeof v === 'object' && v !== null &&
typeof (v as any).enabled === 'boolean'; Prevention
- Always set Content-Type: application/json on PUTs to this API
- Keep booleans as real booleans end-to-end (no string coercion in form state)
- Unit-test request serialization for every toggle endpoint
When it happens
Trigger: PUT /api/system/autostart with: an empty request body (decode returns EOF); truncated or malformed JSON like {"enabled": tru}; sending "enabled":"true" (string instead of bool); a UTF-8 BOM prefix; a JSON array body; or a proxy that strips the body.
Common situations: Frontend sends the toggle state as form data or query string instead of a JSON body; a curl call missing -d entirely; string-typed booleans coming from a config UI state store; double JSON.stringify causing a quoted body.
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
AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15).
Data as JSON: /api/errors/4e7d1bd8b351fcc8.
Report an issue: GitHub.