{"record":{"id":"42ab1d16166917eb","repo":"wavetermdev/waveterm","slug":"internal-server-error-v","errorCode":null,"errorMessage":"internal server error: %v","messagePattern":"internal server error: (.+?)","errorType":"http","errorClass":null,"httpStatus":500,"severity":"critical","filePath":"tsunami/engine/serverhandlers.go","lineNumber":105,"sourceCode":"\tmux.HandleFunc(\"/api/terminput\", h.handleTermInput)\n\tmux.HandleFunc(\"/dyn/\", h.handleDynContent)\n\n\t// Add handler for static files at /static/ path\n\tif opts.StaticFS != nil {\n\t\tmux.HandleFunc(\"/static/\", h.handleStaticPathFiles(opts.StaticFS))\n\t}\n\n\t// Add fallback handler for embedded static files in production mode\n\tif opts.AssetsFS != nil {\n\t\tmux.HandleFunc(\"/\", h.handleStaticFiles(opts.AssetsFS))\n\t}\n}\n\nfunc (h *httpHandlers) handleRender(w http.ResponseWriter, r *http.Request) {\n\tdefer func() {\n\t\tpanicErr := util.PanicHandler(\"handleRender\", recover())\n\t\tif panicErr != nil {\n\t\t\thttp.Error(w, fmt.Sprintf(\"internal server error: %v\", panicErr), http.StatusInternalServerError)\n\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 {","sourceCodeStart":87,"sourceCodeEnd":123,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/tsunami/engine/serverhandlers.go#L87-L123","documentation":"httpHandlers.handleRender (tsunami/engine/serverhandlers.go:105) recovers any panic in the render handler via util.PanicHandler and returns HTTP 500 with 'internal server error: <panic>'. This is a crash of the VDom render pipeline, not a client error.","triggerScenarios":"A panic occurs anywhere inside handleRender after the deferred recover is installed — e.g. nil dereference in the render model, panicking renderer plugin, or index-out-of-range while processing a VDomFrontendUpdate.","commonSituations":"Malformed but structurally-valid JSON updates driving the renderer into an unexpected state, race conditions in engine state accessed by concurrent render requests, or a newly added render component that panics on nil props.","solutions":["Check server logs for the PanicHandler output — it contains the panic message and stack trace identifying the failing code path.","Reproduce with the specific VDomFrontendUpdate payload that triggered the crash and fix the nil/unsafe access in the render handler.","Add nil/len guards around model or props access in the render path.","Retry the render request after the fix; each request runs in its own goroutine so the server itself survives."],"exampleFix":"// before\nnode := renderTree[update.NodeId]\napplyUpdate(node, update) // panics when node is nil\n\n// after\nnode, ok := renderTree[update.NodeId]\nif !ok {\n    log.Printf(\"unknown node %q\", update.NodeId)\n    return\n}\napplyUpdate(node, update)","handlingStrategy":"retry","validationCode":"// sanity-check the update payload before posting so the renderer never sees unexpected shapes\nif (feUpdate == null || typeof feUpdate !== \"object\") throw new Error(\"invalid VDomFrontendUpdate\");","typeGuard":"function isFeUpdate(u) {\n  return u != null && typeof u === \"object\" && \"NodeId\" in u;\n}","tryCatchPattern":"const resp = await fetch(renderUrl, {method: \"POST\", body: JSON.stringify(feUpdate)});\nif (resp.status === 500) {\n  const msg = await resp.text();\n  if (msg.startsWith(\"internal server error\")) {\n    return retryWithBackoff(() => postRender(feUpdate)); // server survived; transient panic may pass on retry\n  }\n  throw new Error(msg);\n}","preventionTips":["Check server logs for the PanicHandler stack trace after any 500 from render.","Guard render-path code against nil nodes/props from client-supplied updates.","Add regression tests reproducing panics from edge-case update payloads."],"tags":["go","http","panic","render"],"backgroundTag":"http-handler-panic","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}