wavetermdev/waveterm · error
failed to parse JSON: %v
Error message
failed to parse JSON: %v
What it means
After reading the body, handleRender unmarshals it into rpctypes.VDomFrontendUpdate; invalid JSON returns HTTP 400 'failed to parse JSON: <err>' (tsunami/engine/serverhandlers.go:124). The embedded error names the exact field/type mismatch.
Source
Thrown at tsunami/engine/serverhandlers.go:124
}
}()
setNoCacheHeaders(w)
if r.Method != http.MethodPost {
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
return
}
body, err := io.ReadAll(r.Body)
if err != nil {
http.Error(w, fmt.Sprintf("failed to read request body: %v", err), http.StatusBadRequest)
return
}
var feUpdate rpctypes.VDomFrontendUpdate
if err := json.Unmarshal(body, &feUpdate); err != nil {
http.Error(w, fmt.Sprintf("failed to parse JSON: %v", err), http.StatusBadRequest)
return
}
if feUpdate.ForceTakeover {
h.Client.clientTakeover(feUpdate.ClientId)
}
if err := h.Client.checkClientId(feUpdate.ClientId); err != nil {
http.Error(w, fmt.Sprintf("client id error: %v", err), http.StatusBadRequest)
return
}
startTime := time.Now()
update, err := h.processFrontendUpdate(&feUpdate)
duration := time.Since(startTime)
if err != nil {
http.Error(w, fmt.Sprintf("render error: %v", err), http.StatusInternalServerError)View on GitHub (pinned to a4447c1563)
Solutions
- Read the wrapped json error to find the offending field/path and fix the payload structure.
- Validate the JSON locally (JSON.parse or a linter) before sending; ensure Content-Type is application/json.
- Marshal the request from the rpctypes.VDomFrontendUpdate type (or its TS equivalent) instead of hand-building the object.
- Check for client/server version mismatch where the VDomFrontendUpdate schema changed; upgrade both sides.
- If sending gzip, declare Content-Encoding so the server receives decoded bytes.
Example fix
// before: invalid payload
await fetch(renderUrl, {method: "POST", body: "{ nodeId: 1 }"}) // unquoted keys
// after
await fetch(renderUrl, {method: "POST", headers: {"Content-Type": "application/json"}, body: JSON.stringify({nodeId: 1, ...feUpdate})}) Defensive patterns
Strategy: validation
Validate before calling
const payload = JSON.stringify(feUpdate);
JSON.parse(payload); // throws locally before the network call if invalid
const resp = await fetch(renderUrl, {method: "POST", headers: {"Content-Type": "application/json"}, body: payload}); Type guard
function isFeUpdate(u) {
return u != null && typeof u === "object" && typeof u.ClientId === "string";
} Try / catch
const resp = await fetch(renderUrl, {method: "POST", body: payload});
if (resp.status === 400) {
const msg = await resp.text();
if (msg.includes("failed to parse JSON")) throw new Error(`schema mismatch with VDomFrontendUpdate: ${msg}`);
} Prevention
- Serialize requests from the VDomFrontendUpdate type rather than hand-built objects.
- Validate JSON payloads locally before sending.
- Keep client and server schema versions in sync; the 400 body names the exact mismatching field.
- Always set Content-Type: application/json and declare any Content-Encoding.
When it happens
Trigger: Posting a body that is not valid JSON, sending the wrong content type/encoding, or a payload whose fields have types that don't match VDomFrontendUpdate (e.g. a string where a number is expected, wrong JSON casing).
Common situations: Hand-crafted curl bodies with unquoted keys or trailing commas, clients sending form-encoded or compressed data without declaring it, SDK version drift so the client emits fields no longer matching rpctypes.VDomFrontendUpdate.
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
- no content available
- Invalid UUID format
- wcloud endpoint not set
- wcloud ping endpoint not set
- invalid AIMessage: %w
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/c877a46fccaded05.
Report an issue: GitHub.