{"record":{"id":"cede9fd98cab6baa","repo":"wavetermdev/waveterm","slug":"http-response-status-response-statustext","errorCode":null,"errorMessage":"HTTP ${response.status}: ${response.statusText}","messagePattern":"HTTP (.+?): (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"tsunami/frontend/src/model/tsunami-model.tsx","lineNumber":444,"sourceCode":"        if (!force && !this.needsUpdate) {\n            return;\n        }\n        this.hasPendingRequest = true;\n        this.needsImmediateUpdate = false;\n        try {\n            const feUpdate = this.createFeUpdate();\n            dlog(\"fe-update\", feUpdate);\n\n            const response = await fetch(\"/api/render\", {\n                method: \"POST\",\n                headers: {\n                    \"Content-Type\": \"application/json\",\n                },\n                body: JSON.stringify(feUpdate),\n            });\n\n            if (!response.ok) {\n                throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n            }\n\n            // Check if EventSource connection is closed and reconnect if needed\n            if (this.serverEventSource && this.serverEventSource.readyState === EventSource.CLOSED) {\n                dlog(\"EventSource connection closed, reconnecting\");\n                this.setupServerEventSource();\n            }\n\n            const backendUpdate: VDomBackendUpdate = await response.json();\n            if (backendUpdate !== null) {\n                restoreVDomElems(backendUpdate);\n                dlog(\"be-update\", backendUpdate);\n                this.handleBackendUpdate(backendUpdate);\n            }\n            dlog(\"update cycle done\");\n        } finally {\n            this.lastUpdateTs = Date.now();\n            this.hasPendingRequest = false;","sourceCodeStart":426,"sourceCodeEnd":462,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/tsunami/frontend/src/model/tsunami-model.tsx#L426-L462","documentation":"_sendRenderRequest POSTs a frontend-update (feUpdate) to the Tsunami render server. Any non-ok HTTP response is converted into this error carrying status and statusText, aborting the render round-trip.","triggerScenarios":"The POST to the render endpoint returns 4xx/5xx — render server not running or restarted, malformed feUpdate rejected with 400/422, server-side crash (500), or auth/proxy rejection.","commonSituations":"Tsunami backend down or listening on a different port than the frontend model expects, request body schema drift after an upgrade, long render timing out at a proxy (504).","solutions":["Log response.status: 400/422 → inspect the feUpdate payload against the server's expected schema; 404 → wrong endpoint/baseUrl; 500 → check server logs; 502/504 → proxy/upstream.","Confirm the Tsunami server is up and its URL matches the model's configured endpoint.","Re-align frontend/backend versions if the feUpdate shape changed.","Retry transient statuses (502/503/504) with backoff; the code already reconnects a closed EventSource, extend that to failed renders."],"exampleFix":"// before\nconst response = await fetch(url, { method: \"POST\", body: JSON.stringify(feUpdate) });\nif (!response.ok) throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n// after\nconst response = await fetch(url, { method: \"POST\", body: JSON.stringify(feUpdate) });\nif (response.status === 503 || response.status === 504) {\n  await sleep(1000); return this._sendRenderRequest(feUpdate); // retry transient\n}\nif (!response.ok) throw new Error(`Render request failed: HTTP ${response.status}: ${await response.text()}`);","handlingStrategy":"retry","validationCode":"const res = await fetch(renderUrl, { method: \"HEAD\" });\nif (!res.ok) throw new Error(`render server not ready at ${renderUrl} (HTTP ${res.status})`);\n// only then send render requests","typeGuard":null,"tryCatchPattern":"try {\n  await this._sendRenderRequest(feUpdate);\n} catch (e) {\n  if (/^HTTP (502|503|504)/.test(e.message)) {\n    await sleep(1000);\n    return this._sendRenderRequest(feUpdate); // retry transient upstream errors\n  }\n  throw e;\n}","preventionTips":["Health-check the render server before sending renders; reconnect/restart if down.","Validate feUpdate against the server schema on upgrades to avoid 400/422s.","Retry 502/503/504 with exponential backoff; fail fast on 4xx.","Include the response body in the thrown error for server-side detail."],"tags":["network","http","fetch","tsunami","render-server"],"backgroundTag":"http-request-failed","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}