[{"data":1,"prerenderedAt":655},["ShallowReactive",2],{"content-query-p6fR3u9zym":3},{"_path":4,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":8,"description":9,"layout":10,"crumb":11,"summary":12,"group":13,"order":14,"code":14,"updated":15,"cta":16,"related":24,"faq":41,"body":57,"_type":648,"_id":649,"_source":650,"_file":651,"_stem":652,"_extension":653,"sitemap":654},"/http-errors/400-vs-422","http-errors",false,"","400 vs 422: Bad Request vs Unprocessable Content","400 vs 422: 400 Bad Request is a malformed request, HTTP 422 Unprocessable Content is valid syntax that fails validation. When to use each.","reference","400 vs 422","400: I can't parse this. 422: I parsed it, and it's invalid.","4xx client errors",400,"2026-10-28",{"eyebrow":17,"title":18,"text":19,"to":20,"label":21,"secondaryTo":22,"secondaryLabel":23},"Webhook Relay","See exactly what the sender posted","Before you debug a 400 or 422, look at the raw request. Webhook Bin gives you a free URL that records every request's headers and body, no signup. When a destination expects a different shape, a Webhook Relay function can reshape the payload in flight.","/webhook-bin/","Open Webhook Bin","/features/transform-webhooks/","Transform webhooks",[25,28,31,34,37,40],{"title":26,"to":27},"401 vs 403","/http-errors/401-vs-403/",{"title":29,"to":30},"409 Conflict","/http-errors/409-conflict/",{"title":32,"to":33},"413 Payload Too Large","/http-errors/413-payload-too-large/",{"title":35,"to":36},"Webhook payload","/glossary/webhook-payload/",{"title":38,"to":39},"500 Internal Server Error","/http-errors/500-internal-server-error/",{"title":23,"to":22},[42,45,48,51,54],{"q":43,"a":44},"What is the difference between 400 and 422?","400 Bad Request means the server couldn't understand the request at all: malformed JSON, a wrong Content-Type, a broken header or a missing required parameter. 422 Unprocessable Content means the request was well formed and the server understood it, but the content fails validation, such as an invalid email address or an end date before the start date.",{"q":46,"a":47},"What does HTTP 422 mean?","HTTP 422 Unprocessable Content, formerly called Unprocessable Entity, means the server understood the content type and the syntax was correct, but it couldn't process the instructions because the data is semantically invalid. It is the usual response for validation errors in Rails, Laravel, FastAPI and the GitHub API.",{"q":49,"a":50},"Should I use 400 or 422 for validation errors?","Both are acceptable, and consistency matters more than the choice. A common convention is 400 for anything the parser rejects and 422 for well-formed requests that fail business or field validation. Whichever you pick, return a body listing which fields failed and why.",{"q":52,"a":53},"Why does my webhook endpoint return 400?","Usually the body isn't what your handler expected. The provider sent form-encoded data and you expected JSON, the event type has a different shape, a field is null, or your framework's body parser rejected the content type. Capture the raw request to see exactly what arrived.",{"q":55,"a":56},"Will a webhook provider retry a 400 or 422?","It depends on the provider. Some retry every non-2xx response, others treat 4xx as permanent and stop. Since the same payload will fail the same way, a 4xx retry rarely helps; fix the handler and replay the event instead.",{"type":58,"children":59,"toc":641},"root",[60,89,206,255,292,299,386,392,433,439,449,459,522,528,541,560,565,603,609,635],{"type":61,"tag":62,"props":63,"children":64},"element","p",{},[65,87],{"type":61,"tag":66,"props":67,"children":68},"strong",{},[69,77,79,85],{"type":61,"tag":70,"props":71,"children":73},"code",{"className":72},[],[74],{"type":75,"value":76},"text","400 Bad Request",{"type":75,"value":78}," means the server couldn't understand the request: the syntax is broken, so it can't even be parsed. ",{"type":61,"tag":70,"props":80,"children":82},{"className":81},[],[83],{"type":75,"value":84},"422 Unprocessable Content",{"type":75,"value":86}," means the request was well formed and understood, but the data fails validation.",{"type":75,"value":88}," Malformed JSON is a 400. Valid JSON with an invalid email address is a 422.",{"type":61,"tag":90,"props":91,"children":92},"table",{},[93,121],{"type":61,"tag":94,"props":95,"children":96},"thead",{},[97],{"type":61,"tag":98,"props":99,"children":100},"tr",{},[101,105,113],{"type":61,"tag":102,"props":103,"children":104},"th",{},[],{"type":61,"tag":102,"props":106,"children":107},{},[108],{"type":61,"tag":70,"props":109,"children":111},{"className":110},[],[112],{"type":75,"value":76},{"type":61,"tag":102,"props":114,"children":115},{},[116],{"type":61,"tag":70,"props":117,"children":119},{"className":118},[],[120],{"type":75,"value":84},{"type":61,"tag":122,"props":123,"children":124},"tbody",{},[125,144,170,188],{"type":61,"tag":98,"props":126,"children":127},{},[128,134,139],{"type":61,"tag":129,"props":130,"children":131},"td",{},[132],{"type":75,"value":133},"Meaning",{"type":61,"tag":129,"props":135,"children":136},{},[137],{"type":75,"value":138},"I can't parse this",{"type":61,"tag":129,"props":140,"children":141},{},[142],{"type":75,"value":143},"I parsed it, and it's invalid",{"type":61,"tag":98,"props":145,"children":146},{},[147,152,165],{"type":61,"tag":129,"props":148,"children":149},{},[150],{"type":75,"value":151},"Examples",{"type":61,"tag":129,"props":153,"children":154},{},[155,157,163],{"type":75,"value":156},"Malformed JSON, wrong ",{"type":61,"tag":70,"props":158,"children":160},{"className":159},[],[161],{"type":75,"value":162},"Content-Type",{"type":75,"value":164},", oversized or broken header, missing required query parameter",{"type":61,"tag":129,"props":166,"children":167},{},[168],{"type":75,"value":169},"Invalid email, unknown enum value, end date before start date, quantity below zero",{"type":61,"tag":98,"props":171,"children":172},{},[173,178,183],{"type":61,"tag":129,"props":174,"children":175},{},[176],{"type":75,"value":177},"Defined in",{"type":61,"tag":129,"props":179,"children":180},{},[181],{"type":75,"value":182},"RFC 9110",{"type":61,"tag":129,"props":184,"children":185},{},[186],{"type":75,"value":187},"RFC 9110 (originally WebDAV, RFC 4918, as \"Unprocessable Entity\")",{"type":61,"tag":98,"props":189,"children":190},{},[191,196,201],{"type":61,"tag":129,"props":192,"children":193},{},[194],{"type":75,"value":195},"Common in",{"type":61,"tag":129,"props":197,"children":198},{},[199],{"type":75,"value":200},"Every server and proxy",{"type":61,"tag":129,"props":202,"children":203},{},[204],{"type":75,"value":205},"Rails, Laravel, FastAPI, the GitHub API",{"type":61,"tag":207,"props":208,"children":212},"pre",{"className":209,"code":210,"language":211,"meta":7,"style":7},"language-http shiki shiki-themes github-dark","HTTP/1.1 400 Bad Request\nContent-Type: application/json\n\n{\"error\": \"invalid_json\", \"message\": \"Unexpected token } in JSON at position 41\"}\n","http",[213],{"type":61,"tag":70,"props":214,"children":215},{"__ignoreMap":7},[216,227,236,246],{"type":61,"tag":217,"props":218,"children":221},"span",{"class":219,"line":220},"line",1,[222],{"type":61,"tag":217,"props":223,"children":224},{},[225],{"type":75,"value":226},"HTTP/1.1 400 Bad Request\n",{"type":61,"tag":217,"props":228,"children":230},{"class":219,"line":229},2,[231],{"type":61,"tag":217,"props":232,"children":233},{},[234],{"type":75,"value":235},"Content-Type: application/json\n",{"type":61,"tag":217,"props":237,"children":239},{"class":219,"line":238},3,[240],{"type":61,"tag":217,"props":241,"children":243},{"emptyLinePlaceholder":242},true,[244],{"type":75,"value":245},"\n",{"type":61,"tag":217,"props":247,"children":249},{"class":219,"line":248},4,[250],{"type":61,"tag":217,"props":251,"children":252},{},[253],{"type":75,"value":254},"{\"error\": \"invalid_json\", \"message\": \"Unexpected token } in JSON at position 41\"}\n",{"type":61,"tag":207,"props":256,"children":258},{"className":209,"code":257,"language":211,"meta":7,"style":7},"HTTP/1.1 422 Unprocessable Content\nContent-Type: application/json\n\n{\"error\": \"validation_failed\", \"fields\": {\"email\": \"is not a valid email address\"}}\n",[259],{"type":61,"tag":70,"props":260,"children":261},{"__ignoreMap":7},[262,270,277,284],{"type":61,"tag":217,"props":263,"children":264},{"class":219,"line":220},[265],{"type":61,"tag":217,"props":266,"children":267},{},[268],{"type":75,"value":269},"HTTP/1.1 422 Unprocessable Content\n",{"type":61,"tag":217,"props":271,"children":272},{"class":219,"line":229},[273],{"type":61,"tag":217,"props":274,"children":275},{},[276],{"type":75,"value":235},{"type":61,"tag":217,"props":278,"children":279},{"class":219,"line":238},[280],{"type":61,"tag":217,"props":281,"children":282},{"emptyLinePlaceholder":242},[283],{"type":75,"value":245},{"type":61,"tag":217,"props":285,"children":286},{"class":219,"line":248},[287],{"type":61,"tag":217,"props":288,"children":289},{},[290],{"type":75,"value":291},"{\"error\": \"validation_failed\", \"fields\": {\"email\": \"is not a valid email address\"}}\n",{"type":61,"tag":293,"props":294,"children":296},"h2",{"id":295},"common-causes-of-400",[297],{"type":75,"value":298},"Common causes of 400",{"type":61,"tag":300,"props":301,"children":302},"ul",{},[303,314,332,358,368],{"type":61,"tag":304,"props":305,"children":306},"li",{},[307,312],{"type":61,"tag":66,"props":308,"children":309},{},[310],{"type":75,"value":311},"Malformed body.",{"type":75,"value":313}," A trailing comma, single quotes, or a body that was truncated.",{"type":61,"tag":304,"props":315,"children":316},{},[317,322,324,330],{"type":61,"tag":66,"props":318,"children":319},{},[320],{"type":75,"value":321},"Content type mismatch.",{"type":75,"value":323}," Sending JSON without ",{"type":61,"tag":70,"props":325,"children":327},{"className":326},[],[328],{"type":75,"value":329},"Content-Type: application/json",{"type":75,"value":331},", or form data to an endpoint expecting JSON.",{"type":61,"tag":304,"props":333,"children":334},{},[335,340,342,348,350,356],{"type":61,"tag":66,"props":336,"children":337},{},[338],{"type":75,"value":339},"Bad headers or cookies.",{"type":75,"value":341}," nginx returns ",{"type":61,"tag":70,"props":343,"children":345},{"className":344},[],[346],{"type":75,"value":347},"400 Bad Request: Request Header Or Cookie Too Large",{"type":75,"value":349}," when headers exceed ",{"type":61,"tag":70,"props":351,"children":353},{"className":352},[],[354],{"type":75,"value":355},"large_client_header_buffers",{"type":75,"value":357},". Clearing the site's cookies fixes it for visitors.",{"type":61,"tag":304,"props":359,"children":360},{},[361,366],{"type":61,"tag":66,"props":362,"children":363},{},[364],{"type":75,"value":365},"Invalid URL.",{"type":75,"value":367}," Unencoded characters in the path or query string.",{"type":61,"tag":304,"props":369,"children":370},{},[371,376,378,384],{"type":61,"tag":66,"props":372,"children":373},{},[374],{"type":75,"value":375},"Plain HTTP to an HTTPS port.",{"type":75,"value":377}," nginx answers ",{"type":61,"tag":70,"props":379,"children":381},{"className":380},[],[382],{"type":75,"value":383},"400 The plain HTTP request was sent to HTTPS port",{"type":75,"value":385},".",{"type":61,"tag":293,"props":387,"children":389},{"id":388},"common-causes-of-422",[390],{"type":75,"value":391},"Common causes of 422",{"type":61,"tag":300,"props":393,"children":394},{},[395,405,423],{"type":61,"tag":304,"props":396,"children":397},{},[398,403],{"type":61,"tag":66,"props":399,"children":400},{},[401],{"type":75,"value":402},"Field validation.",{"type":75,"value":404}," A required field is empty, a string is too long, a format doesn't match.",{"type":61,"tag":304,"props":406,"children":407},{},[408,413,415,421],{"type":61,"tag":66,"props":409,"children":410},{},[411],{"type":75,"value":412},"Business rules.",{"type":75,"value":414}," A coupon that has expired, a duplicate username (some APIs use ",{"type":61,"tag":416,"props":417,"children":418},"a",{"href":30},[419],{"type":75,"value":420},"409",{"type":75,"value":422}," for this), an invalid state transition.",{"type":61,"tag":304,"props":424,"children":425},{},[426,431],{"type":61,"tag":66,"props":427,"children":428},{},[429],{"type":75,"value":430},"Framework defaults.",{"type":75,"value":432}," FastAPI returns 422 for any request that fails its Pydantic model. Rails scaffold controllers return 422 when a record fails to save.",{"type":61,"tag":293,"props":434,"children":436},{"id":435},"how-to-fix-them",[437],{"type":75,"value":438},"How to fix them",{"type":61,"tag":62,"props":440,"children":441},{},[442,447],{"type":61,"tag":66,"props":443,"children":444},{},[445],{"type":75,"value":446},"As a visitor:",{"type":75,"value":448}," for a persistent 400 on one site, clear that site's cookies. Otherwise check the URL for typos.",{"type":61,"tag":62,"props":450,"children":451},{},[452,457],{"type":61,"tag":66,"props":453,"children":454},{},[455],{"type":75,"value":456},"As a developer calling an API:",{"type":75,"value":458}," read the response body. Good APIs say exactly which field failed. Then:",{"type":61,"tag":460,"props":461,"children":462},"ol",{},[463,476,489,501],{"type":61,"tag":304,"props":464,"children":465},{},[466,468,474],{"type":75,"value":467},"Log the exact request you sent, not the object you meant to send. ",{"type":61,"tag":70,"props":469,"children":471},{"className":470},[],[472],{"type":75,"value":473},"curl -v",{"type":75,"value":475}," or your HTTP client's debug mode.",{"type":61,"tag":304,"props":477,"children":478},{},[479,481,487],{"type":75,"value":480},"Validate the JSON (",{"type":61,"tag":70,"props":482,"children":484},{"className":483},[],[485],{"type":75,"value":486},"jq . payload.json",{"type":75,"value":488},").",{"type":61,"tag":304,"props":490,"children":491},{},[492,494,499],{"type":75,"value":493},"Check ",{"type":61,"tag":70,"props":495,"children":497},{"className":496},[],[498],{"type":75,"value":162},{"type":75,"value":500}," and encoding.",{"type":61,"tag":304,"props":502,"children":503},{},[504,506,512,514,520],{"type":75,"value":505},"Compare against the API's schema, including types: ",{"type":61,"tag":70,"props":507,"children":509},{"className":508},[],[510],{"type":75,"value":511},"\"5\"",{"type":75,"value":513}," and ",{"type":61,"tag":70,"props":515,"children":517},{"className":516},[],[518],{"type":75,"value":519},"5",{"type":75,"value":521}," are different.",{"type":61,"tag":293,"props":523,"children":525},{"id":524},"_400-and-422-on-a-webhook-endpoint",[526],{"type":75,"value":527},"400 and 422 on a webhook endpoint",{"type":61,"tag":62,"props":529,"children":530},{},[531,533,539],{"type":75,"value":532},"A webhook handler returning 400 or 422 almost always means the payload isn't the shape the code expected. A provider added a field, sent a different event type, used form encoding, or set a field to ",{"type":61,"tag":70,"props":534,"children":536},{"className":535},[],[537],{"type":75,"value":538},"null",{"type":75,"value":540},". Retrying won't help, because the same payload will fail the same way.",{"type":61,"tag":62,"props":542,"children":543},{},[544,546,551,553,558],{"type":75,"value":545},"Debug it by looking at the raw request rather than guessing. Point the provider (or a copy of its traffic) at a free ",{"type":61,"tag":416,"props":547,"children":548},{"href":20},[549],{"type":75,"value":550},"Webhook Bin",{"type":75,"value":552}," URL and you'll see the exact method, headers and body. If the problem is that your destination expects a different format, such as forwarding one provider's event into another service's API, a Webhook Relay ",{"type":61,"tag":416,"props":554,"children":555},{"href":22},[556],{"type":75,"value":557},"transform function",{"type":75,"value":559}," can rename fields, restructure the JSON or drop events before delivery.",{"type":61,"tag":62,"props":561,"children":562},{},[563],{"type":75,"value":564},"Two rules for webhook handlers:",{"type":61,"tag":300,"props":566,"children":567},{},[568,585],{"type":61,"tag":304,"props":569,"children":570},{},[571,576,578,584],{"type":61,"tag":66,"props":572,"children":573},{},[574],{"type":75,"value":575},"Accept unknown fields and event types.",{"type":75,"value":577}," Ignore what you don't need instead of failing validation on it, and acknowledge unhandled event types with ",{"type":61,"tag":70,"props":579,"children":581},{"className":580},[],[582],{"type":75,"value":583},"200",{"type":75,"value":385},{"type":61,"tag":304,"props":586,"children":587},{},[588,593,595,601],{"type":61,"tag":66,"props":589,"children":590},{},[591],{"type":75,"value":592},"Don't validate before you verify.",{"type":75,"value":594}," Check the ",{"type":61,"tag":416,"props":596,"children":598},{"href":597},"/glossary/webhook-signature/",[599],{"type":75,"value":600},"signature",{"type":75,"value":602}," on the raw body first, then parse and validate.",{"type":61,"tag":293,"props":604,"children":606},{"id":605},"when-to-return-400-vs-422-from-your-own-api",[607],{"type":75,"value":608},"When to return 400 vs 422 from your own API",{"type":61,"tag":62,"props":610,"children":611},{},[612,614,619,621,626,628,633],{"type":75,"value":613},"Pick a convention and keep to it. A clear one: ",{"type":61,"tag":66,"props":615,"children":616},{},[617],{"type":75,"value":618},"400",{"type":75,"value":620}," for anything your parser or router rejects, ",{"type":61,"tag":66,"props":622,"children":623},{},[624],{"type":75,"value":625},"422",{"type":75,"value":627}," for well-formed requests that fail field or business validation. Always return a machine-readable body naming the failing fields. Never return ",{"type":61,"tag":416,"props":629,"children":630},{"href":39},[631],{"type":75,"value":632},"500",{"type":75,"value":634}," for bad input; that's a bug in your validation.",{"type":61,"tag":636,"props":637,"children":638},"style",{},[639],{"type":75,"value":640},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":7,"searchDepth":238,"depth":238,"links":642},[643,644,645,646,647],{"id":295,"depth":229,"text":298},{"id":388,"depth":229,"text":391},{"id":435,"depth":229,"text":438},{"id":524,"depth":229,"text":527},{"id":605,"depth":229,"text":608},"markdown","content:http-errors:400-vs-422.md","content","http-errors/400-vs-422.md","http-errors/400-vs-422","md",{"loc":4},1793199904446]