plandex-ai/plandex · warning

Error decoding request body

Error message

Error decoding request body

What it means

HTTP 400 error returned by UpdatePlanConfigHandler when json.NewDecoder fails to decode the request body into a shared.UpdatePlanConfigRequest. This is a client-side validation failure: the payload is not valid JSON or does not match the expected request shape. Plan authorization has already succeeded, so only the request body itself is at fault.

Source

Thrown at app/server/handlers/plan_config.go:78

	if auth == nil {
		return
	}

	vars := mux.Vars(r)
	planId := vars["planId"]

	log.Println("planId: ", planId)

	plan := authorizePlan(w, planId, auth)
	if plan == nil {
		return
	}

	var req shared.UpdatePlanConfigRequest
	err := json.NewDecoder(r.Body).Decode(&req)
	if err != nil {
		log.Println("Error decoding request body: ", err)
		http.Error(w, "Error decoding request body", http.StatusBadRequest)
		return
	}

	err = db.StorePlanConfig(planId, req.Config)
	if err != nil {
		log.Println("Error storing plan config: ", err)
		http.Error(w, "Error storing plan config", http.StatusInternalServerError)
		return
	}

	log.Println("UpdatePlanConfigHandler processed successfully")
}

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

	auth := Authenticate(w, r, true)
	if auth == nil {

View on GitHub (pinned to e2d772072e)

Solutions

  1. Send a valid JSON body matching shared.UpdatePlanConfigRequest, e.g. {"config": {...}}
  2. Set header Content-Type: application/json
  3. Validate the JSON with a linter or jq before sending
  4. Check for field type mismatches against the latest shared model (client/server version skew)
  5. Log the raw body on the server when this 400 occurs to see what was received

Example fix

// before (curl)
curl -d config={"model":"gpt-4"} ...
// after
curl -H 'Content-Type: application/json' -d '{"config":{"model":"gpt-4"}}' ...
Defensive patterns

Strategy: validation

Validate before calling

// client: validate body before sending
const body = { config: planConfig };
const json = JSON.stringify(body);
if (!json || json === '{}') throw new Error('request body required');
await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: json });

Type guard

function isUpdatePlanConfigRequest(v) {
  return v != null && typeof v === 'object' && 'config' in v && typeof v.config === 'object';
}

Try / catch

try {
  await updatePlanConfig(planId, config);
} catch (e) {
  if (e.status === 400) { /* show user 'invalid JSON body'; do not retry */ }
  else throw e;
}

Prevention

When it happens

Trigger: POST/PUT update-plan-config with non-JSON body, trailing garbage after valid JSON, wrong field types (e.g. string where number expected), sending Content-Length > 0 with an empty body, or forgetting to close the JSON object.

Common situations: Client sending form-encoded data instead of JSON, missing Content-Type handling in scripts, older client versions posting a stale request schema, curl commands with quoting mistakes, proxy stripping the body.

Related errors


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