{"record":{"id":"f1919c9ae9b7b585","repo":"plandex-ai/plandex","slug":"error-parsing-request-body-f1919c","errorCode":null,"errorMessage":"Error parsing request body","messagePattern":"Error parsing request body","errorType":"http","errorClass":null,"httpStatus":400,"severity":"error","filePath":"app/server/handlers/plans_exec.go","lineNumber":65,"sourceCode":"\t}\n\n\tbody, err := io.ReadAll(r.Body)\n\tif err != nil {\n\t\tlog.Printf(\"Error reading request body: %v\\n\", err)\n\t\tgo notify.NotifyErr(notify.SeverityError, fmt.Errorf(\"error reading request body: %v\", err))\n\t\thttp.Error(w, \"Error reading request body\", http.StatusInternalServerError)\n\t\treturn\n\t}\n\tdefer func() {\n\t\tlog.Println(\"Closing request body\")\n\t\tr.Body.Close()\n\t}()\n\n\tvar requestBody shared.TellPlanRequest\n\tif err := json.Unmarshal(body, &requestBody); err != nil {\n\t\tlog.Printf(\"Error parsing request body: %v\\n\", err)\n\t\tgo notify.NotifyErr(notify.SeverityError, fmt.Errorf(\"error parsing request body: %v\", err))\n\t\thttp.Error(w, \"Error parsing request body\", http.StatusBadRequest)\n\t\treturn\n\t}\n\n\t_, apiErr := hooks.ExecHook(hooks.WillTellPlan, hooks.HookParams{\n\t\tAuth: auth,\n\t\tPlan: plan,\n\t})\n\tif apiErr != nil {\n\t\tgo notify.NotifyErr(notify.SeverityError, fmt.Errorf(\"error executing will tell plan hook: %v\", apiErr))\n\t\twriteApiError(w, *apiErr)\n\t\treturn\n\t}\n\n\torgUserConfig, err := db.GetOrgUserConfig(auth.User.Id, auth.OrgId)\n\tif err != nil {\n\t\tlog.Printf(\"Error getting org user config: %v\\n\", err)\n\t\thttp.Error(w, \"Error getting org user config\", http.StatusInternalServerError)\n\t\treturn","sourceCodeStart":47,"sourceCodeEnd":83,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/server/handlers/plans_exec.go#L47-L83","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Validate the JSON body locally with `echo '<payload>' | jq .` or json.Unmarshal in a test before sending.","Upgrade the Plandex CLI to match the server's shared.TellPlanRequest schema (field names/types changed across versions).","Check the server log for the exact json.Unmarshal message (e.g. 'invalid character', 'cannot unmarshal ... into Go value') to pinpoint the offending field.","Send Content-Type: application/json and serialize the body with a JSON encoder rather than string concatenation."],"exampleFix":"// before: hand-built JSON with unquoted key\nbody := []byte(`{apiKeys: {\"OPENAI_API_KEY\": \"sk-...\"}}`)\n// after: struct + json.Marshal guarantees valid JSON\nreq := shared.TellPlanRequest{ApiKeys: map[string]string{\"OPENAI_API_KEY\": \"sk-...\"}}\nbody, _ := json.Marshal(req)","handlingStrategy":"validation","validationCode":"// validate payload before sending\nvar probe map[string]any\nif err := json.Unmarshal(payload, &probe); err != nil {\n    return fmt.Errorf(\"invalid JSON: %w\", err)\n}","typeGuard":"func isValidTellPlanRequest(b []byte) bool {\n    var req shared.TellPlanRequest\n    return json.Unmarshal(b, &req) == nil\n}","tryCatchPattern":"if err := json.Unmarshal(payload, &req); err != nil {\n    var syntaxErr *json.SyntaxError\n    if errors.As(err, &syntaxErr) {\n        return fmt.Errorf(\"bad JSON at offset %d: %w\", syntaxErr.Offset, err)\n    }\n    return err\n}","preventionTips":["Always serialize with json.Marshal from a typed struct, never string concatenation.","Keep CLI and server on matching versions so TellPlanRequest fields align.","Send Content-Type: application/json.","Lint hand-written curl/CI payloads with jq before deployment."],"tags":["http","json","validation","bad-request"],"backgroundTag":"json-unmarshal-failed","analyzedSha":"e2d772072efadbe41d2946d97d79be55532dbab5","analyzedAt":"2026-09-05T20:56:53.631Z","contentChangedAt":"2026-09-05T20:56:53.631Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}