plandex-ai/plandex · error

Error parsing request body

Error message

Error parsing request body

What it means

After reading the body, TellPlanHandler unmarshals it into shared.TellPlanRequest with json.Unmarshal. Malformed JSON (or a type mismatch with the struct fields) triggers this handler, which responds 400 'Error parsing request body' and reports the error asynchronously. It indicates the client sent a body that is not valid JSON matching TellPlanRequest.

Source

Thrown at app/server/handlers/plans_exec.go:65

	}

	body, err := io.ReadAll(r.Body)
	if err != nil {
		log.Printf("Error reading request body: %v\n", err)
		go notify.NotifyErr(notify.SeverityError, fmt.Errorf("error reading request body: %v", err))
		http.Error(w, "Error reading request body", http.StatusInternalServerError)
		return
	}
	defer func() {
		log.Println("Closing request body")
		r.Body.Close()
	}()

	var requestBody shared.TellPlanRequest
	if err := json.Unmarshal(body, &requestBody); err != nil {
		log.Printf("Error parsing request body: %v\n", err)
		go notify.NotifyErr(notify.SeverityError, fmt.Errorf("error parsing request body: %v", err))
		http.Error(w, "Error parsing request body", http.StatusBadRequest)
		return
	}

	_, apiErr := hooks.ExecHook(hooks.WillTellPlan, hooks.HookParams{
		Auth: auth,
		Plan: plan,
	})
	if apiErr != nil {
		go notify.NotifyErr(notify.SeverityError, fmt.Errorf("error executing will tell plan hook: %v", apiErr))
		writeApiError(w, *apiErr)
		return
	}

	orgUserConfig, err := db.GetOrgUserConfig(auth.User.Id, auth.OrgId)
	if err != nil {
		log.Printf("Error getting org user config: %v\n", err)
		http.Error(w, "Error getting org user config", http.StatusInternalServerError)
		return

View on GitHub (pinned to e2d772072e)

Solutions

  1. Validate the JSON body locally with `echo '<payload>' | jq .` or json.Unmarshal in a test before sending.
  2. Upgrade the Plandex CLI to match the server's shared.TellPlanRequest schema (field names/types changed across versions).
  3. Check the server log for the exact json.Unmarshal message (e.g. 'invalid character', 'cannot unmarshal ... into Go value') to pinpoint the offending field.
  4. Send Content-Type: application/json and serialize the body with a JSON encoder rather than string concatenation.

Example fix

// before: hand-built JSON with unquoted key
body := []byte(`{apiKeys: {"OPENAI_API_KEY": "sk-..."}}`)
// after: struct + json.Marshal guarantees valid JSON
req := shared.TellPlanRequest{ApiKeys: map[string]string{"OPENAI_API_KEY": "sk-..."}}
body, _ := json.Marshal(req)
Defensive patterns

Strategy: validation

Validate before calling

// validate payload before sending
var probe map[string]any
if err := json.Unmarshal(payload, &probe); err != nil {
    return fmt.Errorf("invalid JSON: %w", err)
}

Type guard

func isValidTellPlanRequest(b []byte) bool {
    var req shared.TellPlanRequest
    return json.Unmarshal(b, &req) == nil
}

Try / catch

if err := json.Unmarshal(payload, &req); err != nil {
    var syntaxErr *json.SyntaxError
    if errors.As(err, &syntaxErr) {
        return fmt.Errorf("bad JSON at offset %d: %w", syntaxErr.Offset, err)
    }
    return err
}

Prevention

When it happens

Trigger: POST to the tell-plan endpoint with: syntactically invalid JSON, an empty body, wrong types for fields (e.g. ApiKeys as string instead of map), or a JSON array where an object is expected.

Common situations: Older CLI version sending a deprecated request schema; manual curl with unquoted/missing fields; string interpolation corrupting the payload; missing Content-Type combined with hand-built JSON.

Understand the failure class

Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.

Related errors


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