{"record":{"id":"8a9f164c0ed1d2e9","repo":"wavetermdev/waveterm","slug":"method-not-allowed-8a9f16","errorCode":null,"errorMessage":"method not allowed","messagePattern":"method not allowed","errorType":"http","errorClass":null,"httpStatus":405,"severity":"warning","filePath":"tsunami/engine/serverhandlers.go","lineNumber":112,"sourceCode":"\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 {\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}","sourceCodeStart":94,"sourceCodeEnd":130,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/tsunami/engine/serverhandlers.go#L94-L130","documentation":"handleRender only accepts POST; any other method returns HTTP 405 'method not allowed' (tsunami/engine/serverhandlers.go:112). The endpoint consumes a VDomFrontendUpdate JSON body, which only makes sense as a POST.","triggerScenarios":"Issuing GET/PUT/DELETE/OPTIONS to the render endpoint — e.g. opening the URL in a browser (GET), a prefetch preflight, or a misconfigured fetch/axios call defaulting to GET.","commonSituations":"Testing the endpoint by pasting its URL in a browser, an API client wired to the wrong method, CORS preflight or health-check probes hitting the render route.","solutions":["Send the request as POST with a JSON VDomFrontendUpdate body.","Fix the client call: fetch(url, {method: 'POST', headers: {'Content-Type': 'application/json'}, body: ...}).","Point health checks or probes at a dedicated health route instead of the render endpoint.","If GET rendering is needed, add an explicit GET handler rather than reusing this route."],"exampleFix":"// before\nawait fetch(renderUrl) // GET\n\n// after\nawait fetch(renderUrl, {method: \"POST\", headers: {\"Content-Type\": \"application/json\"}, body: JSON.stringify(feUpdate)})","handlingStrategy":"validation","validationCode":"if (feUpdate === undefined) throw new Error(\"render endpoint requires POST with a JSON body\");\nconst resp = await fetch(renderUrl, {method: \"POST\", headers: {\"Content-Type\": \"application/json\"}, body: JSON.stringify(feUpdate)});","typeGuard":null,"tryCatchPattern":"const resp = await fetch(renderUrl, {method: \"POST\", body});\nif (resp.status === 405) throw new Error(\"render endpoint only accepts POST\");","preventionTips":["Always call the render endpoint with method POST and a JSON body.","Do not point browsers, health checks, or prefetchers at the render route.","Centralize the render call in one client helper so the method is never mistyped."],"tags":["go","http","method-not-allowed"],"backgroundTag":"http-method-not-allowed","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}