{"record":{"id":"e6b13ecca94b9f38","repo":"plandex-ai/plandex","slug":"error-decoding-request-v","errorCode":null,"errorMessage":"Error decoding request: %v","messagePattern":"Error decoding request: (.+?)","errorType":"http","errorClass":null,"httpStatus":400,"severity":"warning","filePath":"app/server/handlers/file_maps.go","lineNumber":29,"sourceCode":"\t\"sync\"\n\n\tshared \"plandex-shared\"\n\n\t\"github.com/gorilla/mux\"\n)\n\nfunc GetFileMapHandler(w http.ResponseWriter, r *http.Request) {\n\tlog.Println(\"Received request for GetFileMapHandler\")\n\n\tauth := Authenticate(w, r, true)\n\tif auth == nil {\n\t\tlog.Println(\"GetFileMapHandler: auth failed\")\n\t\treturn\n\t}\n\n\tvar req shared.GetFileMapRequest\n\tif err := json.NewDecoder(r.Body).Decode(&req); err != nil {\n\t\thttp.Error(w, fmt.Sprintf(\"Error decoding request: %v\", err), http.StatusBadRequest)\n\t\treturn\n\t}\n\n\tlog.Println(\"GetFileMapHandler: checking limits\")\n\n\tif len(req.MapInputs) > shared.MaxContextMapPaths {\n\t\thttp.Error(w, fmt.Sprintf(\"Too many files to map: %d (max %d)\", len(req.MapInputs), shared.MaxContextMapPaths), http.StatusBadRequest)\n\t\treturn\n\t}\n\n\ttotalSize := 0\n\tfor path, input := range req.MapInputs {\n\t\t// the client should be truncating inputs to the max size, but we'll check here too\n\t\tif len(input) > shared.MaxContextMapSingleInputSize {\n\t\t\thttp.Error(w, fmt.Sprintf(\"File %s is too large: %d (max %d)\", path, len(input), shared.MaxContextMapSingleInputSize), http.StatusBadRequest)\n\t\t\treturn\n\t\t}\n\t\ttotalSize += len(input)","sourceCodeStart":11,"sourceCodeEnd":47,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/server/handlers/file_maps.go#L11-L47","documentation":"GetFileMapHandler decodes the request body into shared.GetFileMapRequest using json.NewDecoder. If the body is not valid JSON or does not match the request schema, it logs 'Error decoding request: %v' (the %v is filled with the actual decode error) and returns HTTP 400 with the message.","triggerScenarios":"POST to the file-map endpoint with a malformed/empty body, invalid JSON syntax, wrong field types (e.g. MapInputs as an array instead of map[string]string), or a body already consumed by a middleware.","commonSituations":"Client sends form-encoded or gzip data instead of JSON; a proxy strips or truncates the body; client SDK version mismatch sends an older schema; Content-Type set but body left empty; double-reading r.Body (e.g. in logging middleware) leaving nothing for the decoder.","solutions":["Log/print the exact decode error from the 400 response body and fix the JSON at the call site","Verify the client sends application/json with a body matching shared.GetFileMapRequest: {\"MapInputs\": map[string]string}","If middleware reads the body, re-set r.Body with io.NopCloser(bytes.NewBuffer(saved)) before the handler","Ensure the client serializes with json.Marshal (or equivalent) rather than hand-built strings"],"exampleFix":"// before\nhttp.Post(url, \"text/plain\", strings.NewReader(\"paths=/a.go,/b.go\"))\n// after\nbody, _ := json.Marshal(shared.GetFileMapRequest{MapInputs: inputs})\nhttp.Post(url, \"application/json\", bytes.NewReader(body))","handlingStrategy":"validation","validationCode":"// Client-side pre-send validation\nbody, err := json.Marshal(shared.GetFileMapRequest{MapInputs: inputs})\nif err != nil { return fmt.Errorf(\"invalid request: %w\", err) }\nvar probe shared.GetFileMapRequest\nif err := json.Unmarshal(body, &probe); err != nil { return err }","typeGuard":"func isValidGetFileMapRequest(body []byte) bool {\n    var req shared.GetFileMapRequest\n    return json.Unmarshal(body, &req) == nil && req.MapInputs != nil\n}","tryCatchPattern":null,"preventionTips":["Always send Content-Type: application/json with json.Marshal output","Round-trip the payload through Unmarshal before sending in tests","Don't read r.Body in middleware without restoring it","Log the raw body on decode failure to spot schema drift early"],"tags":["go","json","http","bad-request"],"backgroundTag":"request-body-decode-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"}