{"id":"f166cb73b15ab87f","repo":"gin-gonic/gin","slug":"invalid-request","errorCode":null,"errorMessage":"invalid request","messagePattern":"invalid request","errorType":"validation","errorClass":null,"httpStatus":400,"severity":"error","filePath":"binding/json.go","lineNumber":35,"sourceCode":"// Decoder instance. UseNumber causes the Decoder to unmarshal a number into an\n// any as a Number instead of as a float64.\nvar EnableDecoderUseNumber = false\n\n// EnableDecoderDisallowUnknownFields is used to call the DisallowUnknownFields method\n// on the JSON Decoder instance. DisallowUnknownFields causes the Decoder to\n// return an error when the destination is a struct and the input contains object\n// keys which do not match any non-ignored, exported fields in the destination.\nvar EnableDecoderDisallowUnknownFields = false\n\ntype jsonBinding struct{}\n\nfunc (jsonBinding) Name() string {\n\treturn \"json\"\n}\n\nfunc (jsonBinding) Bind(req *http.Request, obj any) error {\n\tif req == nil || req.Body == nil {\n\t\treturn errors.New(\"invalid request\")\n\t}\n\treturn decodeJSON(req.Body, obj)\n}\n\nfunc (jsonBinding) BindBody(body []byte, obj any) error {\n\treturn decodeJSON(bytes.NewReader(body), obj)\n}\n\nfunc decodeJSON(r io.Reader, obj any) error {\n\tdecoder := json.API.NewDecoder(r)\n\tif EnableDecoderUseNumber {\n\t\tdecoder.UseNumber()\n\t}\n\tif EnableDecoderDisallowUnknownFields {\n\t\tdecoder.DisallowUnknownFields()\n\t}\n\tif err := decoder.Decode(obj); err != nil {\n\t\treturn err","sourceCodeStart":17,"sourceCodeEnd":53,"githubUrl":"https://github.com/gin-gonic/gin/blob/34dac209ffb6ef85cc78c5d217bbb7ad001d68fd/binding/json.go#L17-L53","documentation":"Returned by jsonBinding.Bind (binding/json.go:35) when the supplied *http.Request is nil OR its Body is nil. The JSON decoder needs a non-nil io.Reader, so Gin refuses before attempting to read. This only happens when the JSON binding is invoked directly with a malformed request object, not during normal c.JSON-style handlers.","triggerScenarios":"Calling binding.JSON.Bind(req, &obj) with req == nil; calling it on an http.Request whose Body was already consumed and not reset (Body becomes nil after Close); constructing an http.Request by hand without setting Body.","commonSituations":"Re-binding the same request twice (first read closes the body); unit tests that build *http.Request without http.NewRequest; middleware that sets c.Request.Body = nil.","solutions":["Ensure the handler reads the body at most once; if you must re-read, reset it via io.NopCloser(bytes.NewBuffer(raw)) before the second bind.","In tests, build the request with http.NewRequest(http.MethodPost, url, strings.NewReader(json)) so Body is non-nil.","Guard the handler: if c.Request == nil || c.Request.Body == nil, short-circuit with a 400 before calling ShouldBindJSON."],"exampleFix":"// before\nraw, _ := io.ReadAll(c.Request.Body)\nvar a A; binding.JSON.Bind(c.Request, &a) // Body now consumed/nil\n// after\nraw, _ := io.ReadAll(c.Request.Body)\nc.Request.Body = io.NopCloser(bytes.NewBuffer(raw))\nvar a A; c.ShouldBindJSON(&a)","handlingStrategy":"validation","validationCode":"if req == nil || req.Body == nil {\n    return errors.New(\"request or body is nil; cannot bind JSON\")\n}\nreturn binding.JSON.Bind(req, obj)","typeGuard":null,"tryCatchPattern":"if err := binding.JSON.Bind(req, &obj); err != nil {\n    if err.Error() == \"invalid request\" {\n        // req or body was nil; reset body and retry, or return 400\n    }\n}","preventionTips":["Never read c.Request.Body twice; reset it via io.NopCloser(bytes.NewBuffer(raw)) if you must.","Build requests in tests with http.NewRequest so Body is always set.","Centralise body reading in one middleware/handler per request."],"tags":["binding","json","request","go"],"analyzedSha":"34dac209ffb6ef85cc78c5d217bbb7ad001d68fd","analyzedAt":"2026-08-04T21:26:18.438Z","schemaVersion":2}