{"record":{"id":"c877a46fccaded05","repo":"wavetermdev/waveterm","slug":"failed-to-parse-json-v","errorCode":null,"errorMessage":"failed to parse JSON: %v","messagePattern":"failed to parse JSON: (.+?)","errorType":"http","errorClass":null,"httpStatus":400,"severity":"error","filePath":"tsunami/engine/serverhandlers.go","lineNumber":124,"sourceCode":"\t\t}\n\t}()\n\n\tsetNoCacheHeaders(w)\n\n\tif r.Method != http.MethodPost {\n\t\thttp.Error(w, \"method not allowed\", http.StatusMethodNotAllowed)\n\t\treturn\n\t}\n\n\tbody, err := io.ReadAll(r.Body)\n\tif err != nil {\n\t\thttp.Error(w, fmt.Sprintf(\"failed to read request body: %v\", err), http.StatusBadRequest)\n\t\treturn\n\t}\n\n\tvar feUpdate rpctypes.VDomFrontendUpdate\n\tif err := json.Unmarshal(body, &feUpdate); err != nil {\n\t\thttp.Error(w, fmt.Sprintf(\"failed to parse JSON: %v\", err), http.StatusBadRequest)\n\t\treturn\n\t}\n\n\tif feUpdate.ForceTakeover {\n\t\th.Client.clientTakeover(feUpdate.ClientId)\n\t}\n\n\tif err := h.Client.checkClientId(feUpdate.ClientId); err != nil {\n\t\thttp.Error(w, fmt.Sprintf(\"client id error: %v\", err), http.StatusBadRequest)\n\t\treturn\n\t}\n\n\tstartTime := time.Now()\n\tupdate, err := h.processFrontendUpdate(&feUpdate)\n\tduration := time.Since(startTime)\n\n\tif err != nil {\n\t\thttp.Error(w, fmt.Sprintf(\"render error: %v\", err), http.StatusInternalServerError)","sourceCodeStart":106,"sourceCodeEnd":142,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/tsunami/engine/serverhandlers.go#L106-L142","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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."],"exampleFix":"// before: invalid payload\nawait fetch(renderUrl, {method: \"POST\", body: \"{ nodeId: 1 }\"}) // unquoted keys\n\n// after\nawait fetch(renderUrl, {method: \"POST\", headers: {\"Content-Type\": \"application/json\"}, body: JSON.stringify({nodeId: 1, ...feUpdate})})","handlingStrategy":"validation","validationCode":"const payload = JSON.stringify(feUpdate);\nJSON.parse(payload); // throws locally before the network call if invalid\nconst resp = await fetch(renderUrl, {method: \"POST\", headers: {\"Content-Type\": \"application/json\"}, body: payload});","typeGuard":"function isFeUpdate(u) {\n  return u != null && typeof u === \"object\" && typeof u.ClientId === \"string\";\n}","tryCatchPattern":"const resp = await fetch(renderUrl, {method: \"POST\", body: payload});\nif (resp.status === 400) {\n  const msg = await resp.text();\n  if (msg.includes(\"failed to parse JSON\")) throw new Error(`schema mismatch with VDomFrontendUpdate: ${msg}`);\n}","preventionTips":["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."],"tags":["go","http","json","validation"],"backgroundTag":"json-parse-failed","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}