{"record":{"id":"f1cbeeee3a9a5c85","repo":"plandex-ai/plandex","slug":"error-parsing-request-body-f1cbee","errorCode":null,"errorMessage":"Error parsing request body","messagePattern":"Error parsing request body","errorType":"http","errorClass":null,"httpStatus":400,"severity":"warning","filePath":"app/server/handlers/plans_changes.go","lineNumber":138,"sourceCode":"\tif plan == nil {\n\t\treturn\n\t}\n\n\tvar err error\n\n\t// read the request body\n\tbody, err := io.ReadAll(r.Body)\n\tif err != nil {\n\t\tlog.Printf(\"Error reading request body: %v\\n\", err)\n\t\thttp.Error(w, \"Error reading request body\", http.StatusInternalServerError)\n\t\treturn\n\t}\n\tdefer r.Body.Close()\n\n\tvar requestBody shared.ApplyPlanRequest\n\tif err := json.Unmarshal(body, &requestBody); err != nil {\n\t\tlog.Printf(\"Error parsing request body: %v\\n\", err)\n\t\thttp.Error(w, \"Error parsing request body\", http.StatusBadRequest)\n\t\treturn\n\t}\n\n\t// Just in case this was sent immediately after a stream finished, wait a little before locking to allow for cleanup\n\ttime.Sleep(100 * time.Millisecond)\n\n\tctx, cancel := context.WithCancel(r.Context())\n\n\tvar settings *shared.PlanSettings\n\tvar currentPlanParams db.CurrentPlanStateParams\n\tvar currentPlan *shared.CurrentPlanState\n\n\terr = db.ExecRepoOperation(db.ExecRepoOperationParams{\n\t\tOrgId:    auth.OrgId,\n\t\tUserId:   auth.User.Id,\n\t\tPlanId:   planId,\n\t\tBranch:   branch,\n\t\tScope:    db.LockScopeRead,","sourceCodeStart":120,"sourceCodeEnd":156,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/server/handlers/plans_changes.go#L120-L156","documentation":"ApplyPlanHandler read the body but json.Unmarshal(body, &requestBody) failed to parse it into shared.ApplyPlanRequest, returning HTTP 400 'Error parsing request body'. The payload is not valid JSON or its fields do not match the struct.","triggerScenarios":"Body is not JSON (HTML error page captured, empty body, multipart form); fields have wrong types (e.g. sessionId as number); sending apiKeys as a string instead of object.","commonSituations":"Client posting form-encoded data instead of JSON; a gateway returning an error page body that gets re-posted; API version mismatch where ApplyPlanRequest fields changed; shell quoting stripping JSON braces.","solutions":["Send a valid JSON object matching ApplyPlanRequest (e.g. {\"sessionId\": \"...\", \"apiKeys\": {...}}) with Content-Type: application/json","Print the raw body client-side before sending to confirm it is intact JSON","Align client and server plandex-shared versions so the request struct matches","Avoid shell interpolation of JSON; use @file or a proper HTTP client"],"exampleFix":"// before\nhttp.post(url, 'sessionId=' + id) // form-encoded\n// after\nhttp.post(url, JSON.stringify({sessionId: id}), {headers: {'Content-Type': 'application/json'}})","handlingStrategy":"validation","validationCode":"const payload = {sessionId, apiKeys, openAIOrgId, authVars};\nconst raw = JSON.stringify(payload);\nJSON.parse(raw); // fail fast locally before the request","typeGuard":"function isApplyPlanRequest(v) {\n  return typeof v === 'object' && v !== null &&\n    (v.sessionId === undefined || typeof v.sessionId === 'string') &&\n    (v.apiKeys === undefined || typeof v.apiKeys === 'object');\n}","tryCatchPattern":"const res = await fetch(applyUrl, opts);\nif (res.status === 400 && (await res.text()).includes('Error parsing request body')) {\n  // body was not valid ApplyPlanRequest JSON — inspect and fix payload\n}","preventionTips":["Send JSON bodies with Content-Type: application/json","Validate field types (sessionId: string, apiKeys: object) before sending","Keep client/server shared schema versions aligned","Never echo a prior error-page body into a new request"],"tags":["http","json","request-body","bad-request"],"backgroundTag":"json-decode-failed","analyzedSha":"e2d772072efadbe41d2946d97d79be55532dbab5","analyzedAt":"2026-09-05T20:56:53.631Z","contentChangedAt":"2026-09-05T20:56:53.631Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}