plandex-ai/plandex · error · http

Error reading request body:

Error message

Error reading request body: 

What it means

CreateEmailVerificationHandler in sessions.go reads the entire request body with io.ReadAll(r.Body) before JSON-decoding it. When that read fails it returns 500 with "Error reading request body: <err>". This is an I/O-level failure while consuming the client's request stream, not a JSON formatting problem.

Source

Thrown at app/server/handlers/sessions.go:25

	"io"
	"log"
	"net/http"
	"os"
	"plandex-server/db"
	"plandex-server/email"
	"strings"

	shared "plandex-shared"
)

func CreateEmailVerificationHandler(w http.ResponseWriter, r *http.Request) {
	log.Println("Received request for CreateEmailVerificationHandler")

	// read the request body
	body, err := io.ReadAll(r.Body)
	if err != nil {
		log.Printf("Error reading request body: %v\n", err)
		http.Error(w, "Error reading request body: "+err.Error(), http.StatusInternalServerError)
		return
	}

	var req shared.CreateEmailVerificationRequest
	err = json.Unmarshal(body, &req)
	if err != nil {
		log.Printf("Error unmarshalling request: %v\n", err)
		http.Error(w, "Error unmarshalling request: "+err.Error(), http.StatusInternalServerError)
		return
	}
	req.Email = strings.ToLower(req.Email)

	var hasAccount bool
	if req.UserId == "" {
		user, err := db.GetUserByEmail(req.Email)

		if err != nil {
			log.Printf("Error getting user: %v\n", err)

View on GitHub (pinned to e2d772072e)

Solutions

  1. Retry the request from the client with a stable connection and the full JSON body (application/json, correct Content-Length).
  2. If behind a proxy (nginx/ALB), raise client_max_body_size / body timeout limits and check proxy error logs for truncation.
  3. If a MaxBytesReader is in use, send a smaller body — this endpoint only needs email/userId flags, not large payloads.
  4. Check the server log line accompanying the 500 for the wrapped error (unexpected EOF vs connection reset) to identify client abort vs proxy truncation.

Example fix

// before (client)
http.Post(url, "application/json", nil) // empty body, mismatched Content-Length
// after
body := []byte(`{"email":"user@example.com","requireUser":true}`)
http.Post(url, "application/json", bytes.NewReader(body))
Defensive patterns

Strategy: validation

Validate before calling

// client-side check before calling the endpoint
payload, _ := json.Marshal(req)
if len(payload) == 0 {
    return errors.New("refusing to send empty request body")
}
httpReq, _ := http.NewRequest(http.MethodPost, url, bytes.NewReader(payload))
httpReq.Header.Set("Content-Type", "application/json")
httpReq.ContentLength = int64(len(payload))

Try / catch

// Go client: wrap the call and distinguish transport-level failures worth retrying
resp, err := client.Do(httpReq)
if err != nil {
    if errors.Is(err, io.ErrUnexpectedEOF) || errors.Is(err, syscall.ECONNRESET) {
        return retryWithBackoff(httpReq)
    }
    return fmt.Errorf("request body failed to send: %w", err)
}

Prevention

When it happens

Trigger: The HTTP client aborts/disconnects while the server is still reading the request body; a reverse proxy truncates the body; the body exceeds a server-side limit (e.g. http.MaxBytesReader wrapping r.Body) causing a read error; TLS/connection reset mid-upload.

Common situations: Flaky mobile/CLI network dropping mid-request; client sends Content-Length larger than the actual body then closes; a proxy with a small request-body timeout; requests to the email-verification endpoint made with curl/clients that hang up early on redirects.

Related errors


AI-assisted analysis of plandex-ai/plandex@e2d772072e (2026-09-05). Data as JSON: /api/errors/0e13ee43ef780095. Report an issue: GitHub.