wavetermdev/waveterm · error

failed to read request body: %v

Error message

failed to read request body: %v

What it means

handleRender reads the entire request body with io.ReadAll; a read failure returns HTTP 400 'failed to read request body: <err>' (tsunami/engine/serverhandlers.go:118). The client's request was malformed or the connection broke mid-upload.

Source

Thrown at tsunami/engine/serverhandlers.go:118

func (h *httpHandlers) handleRender(w http.ResponseWriter, r *http.Request) {
	defer func() {
		panicErr := util.PanicHandler("handleRender", recover())
		if panicErr != nil {
			http.Error(w, fmt.Sprintf("internal server error: %v", panicErr), http.StatusInternalServerError)
		}
	}()

	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
	}

View on GitHub (pinned to a4447c1563)

Solutions

  1. Inspect the wrapped error (unexpected EOF, body too large) to pick the right fix.
  2. Retry the POST; transient disconnects resolve on resend.
  3. Reduce payload size or raise body-size limits on the server/proxy.
  4. Ensure the client fully writes the body before reading the response and does not cancel the request early.

Example fix

// before: aborting mid-send
c.abort() // while fetch body still uploading

// after: await the request completion
await fetch(renderUrl, {method: "POST", body: JSON.stringify(feUpdate), signal: controller.signal})
Defensive patterns

Strategy: retry

Validate before calling

const payload = JSON.stringify(feUpdate);
if (payload.length > MAX_BODY_BYTES) throw new Error("render payload too large");

Try / catch

const resp = await fetch(renderUrl, {method: "POST", body: payload});
if (resp.status === 400 && (await resp.text()).includes("failed to read request body")) {
  return retryWithBackoff(() => fetch(renderUrl, {method: "POST", body: payload}));
}

Prevention

When it happens

Trigger: The HTTP body is truncated by a disconnect, a body-size limit trips, or the client aborts the POST before finishing the upload.

Common situations: Large render payloads over unstable connections, proxy timeouts cutting uploads short, test harnesses sending a closed/empty body reader.

Related errors


AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01). Data as JSON: /api/errors/6c788c0693794711. Report an issue: GitHub.