[{"data":1,"prerenderedAt":1801},["ShallowReactive",2],{"en-post-\u002Fen\u002Fhttp-status-codes-guide":3},{"id":4,"title":5,"body":6,"description":1788,"extension":1789,"meta":1790,"navigation":1140,"path":1796,"seo":1797,"sitemap":1798,"stem":1799,"__hash__":1800},"blogEn\u002Fen\u002Fhttp-status-codes-guide.md","Using HTTP Status Codes Correctly: 400 vs 422, 401 vs 403, and 200 vs 201 vs 204",{"type":7,"value":8,"toc":1774},"minimark",[9,14,18,29,32,61,72,75,79,159,178,180,184,247,258,264,291,293,297,302,348,358,362,408,419,423,444,448,521,524,1331,1333,1337,1415,1426,1437,1439,1443,1458,1554,1577,1603,1605,1609,1754,1770],[10,11,13],"h2",{"id":12},"it-failed-but-its-200-ok","It failed, but it's 200 OK?",[15,16,17],"p",{},"You've probably seen an API response like this:",[19,20,25],"pre",{"className":21,"code":23,"language":24},[22],"language-text","HTTP\u002F1.1 200 OK\n\n{ \"success\": false, \"message\": \"User does not exist\" }\n","text",[26,27,23],"code",{"__ignoreMap":28},"",[15,30,31],{},"The request failed, but the status code says \"success.\" That causes a chain of problems:",[33,34,35,55,58],"ul",{},[36,37,38,39,42,43,46,47,50,51,54],"li",{},"On the frontend, ",[26,40,41],{},"fetch","'s ",[26,44,45],{},"res.ok"," is ",[26,48,49],{},"true",", so every response body has to be opened and checked for ",[26,52,53],{},"success",".",[36,56,57],{},"Error monitoring, load balancers, and CDNs can't recognize failures. The dashboard shows a 0% error rate while users keep failing.",[36,59,60],{},"A failure response might even get cached as a \"success.\"",[62,63,64],"blockquote",{},[15,65,66,67,71],{},"HTTP status codes are an agreement that tells you ",[68,69,70],"strong",{},"what kind of result"," you got without opening the body. Browsers, proxies, monitoring tools, and client libraries all decide what to do based on this number.",[73,74],"hr",{},[10,76,78],{"id":77},"the-first-digit-gets-you-halfway","The first digit gets you halfway",[80,81,82,98],"table",{},[83,84,85],"thead",{},[86,87,88,92,95],"tr",{},[89,90,91],"th",{},"Range",[89,93,94],{},"Meaning",[89,96,97],{},"Whose problem?",[99,100,101,115,127,143],"tbody",{},[86,102,103,109,112],{},[104,105,106],"td",{},[26,107,108],{},"2xx",[104,110,111],{},"Success",[104,113,114],{},"-",[86,116,117,122,125],{},[104,118,119],{},[26,120,121],{},"3xx",[104,123,124],{},"Go somewhere else (redirect, use the cache)",[104,126,114],{},[86,128,129,134,140],{},[104,130,131],{},[26,132,133],{},"4xx",[104,135,136,139],{},[68,137,138],{},"The client"," sent a bad request",[104,141,142],{},"Fix the request",[86,144,145,150,156],{},[104,146,147],{},[26,148,149],{},"5xx",[104,151,152,155],{},[68,153,154],{},"The server"," failed while handling it",[104,157,158],{},"Fix the server",[15,160,161,162,164,165,167,168,170,171,173,174,177],{},"The most important split is ",[26,163,133],{}," vs ",[26,166,149],{},". Bad input is ",[26,169,133],{},"; an exception in server code is ",[26,172,149],{},". Return ",[26,175,176],{},"500"," for a user's typo and your outage alert goes off, waking up the wrong person at 3 a.m.",[73,179],{},[10,181,183],{"id":182},"success-200-201-204","Success: 200, 201, 204",[80,185,186,199],{},[83,187,188],{},[86,189,190,193,196],{},[89,191,192],{},"Code",[89,194,195],{},"When",[89,197,198],{},"Example",[99,200,201,214,231],{},[86,202,203,208,211],{},[104,204,205],{},[26,206,207],{},"200 OK",[104,209,210],{},"Regular success with a body",[104,212,213],{},"Listing items, returning the result of an update",[86,215,216,221,228],{},[104,217,218],{},[26,219,220],{},"201 Created",[104,222,223,224,227],{},"You ",[68,225,226],{},"created"," a new resource",[104,229,230],{},"Sign-up, creating a post",[86,232,233,238,244],{},[104,234,235],{},[26,236,237],{},"204 No Content",[104,239,240,241],{},"Success with ",[68,242,243],{},"no body to return",[104,245,246],{},"Deleting, updates with no response body",[15,248,249,250,253,254,257],{},"With ",[26,251,252],{},"201",", it's customary to put the new resource's URL in the ",[26,255,256],{},"Location"," header.",[19,259,262],{"className":260,"code":261,"language":24},[22],"HTTP\u002F1.1 201 Created\nLocation: \u002Fusers\u002F42\n\n{ \"id\": 42, \"name\": \"kim\" }\n",[26,263,261],{"__ignoreMap":28},[265,266,267],"warning",{},[62,268,269],{},[15,270,271,272,275,276,279,280,283,284,286,287,290],{},"A ",[26,273,274],{},"204"," response has no body. If your frontend calls ",[26,277,278],{},"await res.json()"," out of habit, you'll get a ",[26,281,282],{},"SyntaxError",". For requests that return ",[26,285,274],{},", like delete endpoints, check ",[26,288,289],{},"res.status === 204"," first.",[73,292],{},[10,294,296],{"id":295},"the-most-confusing-4xx-codes","The most confusing 4xx codes",[298,299,301],"h3",{"id":300},"_400-vs-422-broken-format-or-invalid-content","400 vs 422: broken format, or invalid content?",[80,303,304,314],{},[83,305,306],{},[86,307,308,310,312],{},[89,309,192],{},[89,311,94],{},[89,313,198],{},[99,315,316,332],{},[86,317,318,323,329],{},[104,319,320],{},[26,321,322],{},"400 Bad Request",[104,324,325,326],{},"The request ",[68,327,328],{},"can't be parsed",[104,330,331],{},"Broken JSON syntax, a required parameter of the wrong type entirely",[86,333,334,339,345],{},[104,335,336],{},[26,337,338],{},"422 Unprocessable Content",[104,340,341,342],{},"The format is fine, but ",[68,343,344],{},"the content breaks the rules",[104,346,347],{},"Invalid email format, password shorter than 8 characters",[15,349,350,351,354,355,54],{},"Plenty of teams return ",[26,352,353],{},"400"," for every validation failure, and that's not wrong. What matters is ",[68,356,357],{},"being consistent within one API",[298,359,361],{"id":360},"_401-vs-403-we-dont-know-you-or-we-know-you-but-no","401 vs 403: we don't know you, or we know you but no",[80,363,364,375],{},[83,365,366],{},[86,367,368,370,372],{},[89,369,192],{},[89,371,94],{},[89,373,374],{},"What the client should do",[99,376,377,393],{},[86,378,379,384,390],{},[104,380,381],{},[26,382,383],{},"401 Unauthorized",[104,385,386,389],{},[68,387,388],{},"We don't know who you are"," (not logged in, expired token)",[104,391,392],{},"Send to login or refresh the token",[86,394,395,400,405],{},[104,396,397],{},[26,398,399],{},"403 Forbidden",[104,401,402],{},[68,403,404],{},"We know who you are, but you lack permission",[104,406,407],{},"Show a \"no permission\" message (logging in again won't help)",[15,409,410,411,414,415,418],{},"The name ",[26,412,413],{},"Unauthorized"," is confusing, but ",[26,416,417],{},"401"," actually means \"not authenticated.\" Mix the two up and a user without permission gets bounced to the login screen in an endless loop.",[298,420,422],{"id":421},"hiding-existence-with-404","Hiding existence with 404",[15,424,425,426,429,430,433,434,437,438,440,441,443],{},"When ",[68,427,428],{},"the fact that something exists is itself sensitive",", like someone else's private post, you may return ",[26,431,432],{},"404"," instead of ",[26,435,436],{},"403",". A ",[26,439,436],{}," effectively says \"it's there, but you can't see it.\" GitHub returns ",[26,442,432],{}," for private repositories you can't access.",[298,445,447],{"id":446},"other-common-4xx-codes","Other common 4xx codes",[80,449,450,460],{},[83,451,452],{},[86,453,454,456,458],{},[89,455,192],{},[89,457,195],{},[89,459,198],{},[99,461,462,475,491,504],{},[86,463,464,469,472],{},[104,465,466],{},[26,467,468],{},"404 Not Found",[104,470,471],{},"The resource doesn't exist",[104,473,474],{},"A deleted post",[86,476,477,482,485],{},[104,478,479],{},[26,480,481],{},"405 Method Not Allowed",[104,483,484],{},"The method isn't supported at that URL",[104,486,487,490],{},[26,488,489],{},"DELETE"," on a read-only endpoint",[86,492,493,498,501],{},[104,494,495],{},[26,496,497],{},"409 Conflict",[104,499,500],{},"Conflicts with the current state",[104,502,503],{},"Signing up with an email already in use, concurrent edit conflict",[86,505,506,511,514],{},[104,507,508],{},[26,509,510],{},"429 Too Many Requests",[104,512,513],{},"Rate limit exceeded",[104,515,516,517,520],{},"Too many login attempts (say how long to wait with ",[26,518,519],{},"Retry-After",")",[15,522,523],{},"Pick a situation in the preview below.",[525,526,527,609,849],"code-group",{},[19,528,532],{"className":529,"code":530,"language":531,"meta":28,"style":28},"language-html shiki shiki-themes github-light github-dark","\u003Clabel for=\"situation\">Pick a situation\u003C\u002Flabel>\n\u003Cselect id=\"situation\">\u003C\u002Fselect>\n\u003Cdiv id=\"answer\">\u003C\u002Fdiv>\n","html",[26,533,534,566,588],{"__ignoreMap":28},[535,536,539,543,547,551,554,558,561,563],"span",{"class":537,"line":538},"line",1,[535,540,542],{"class":541},"sVt8B","\u003C",[535,544,546],{"class":545},"s9eBZ","label",[535,548,550],{"class":549},"sScJk"," for",[535,552,553],{"class":541},"=",[535,555,557],{"class":556},"sZZnC","\"situation\"",[535,559,560],{"class":541},">Pick a situation\u003C\u002F",[535,562,546],{"class":545},[535,564,565],{"class":541},">\n",[535,567,569,571,574,577,579,581,584,586],{"class":537,"line":568},2,[535,570,542],{"class":541},[535,572,573],{"class":545},"select",[535,575,576],{"class":549}," id",[535,578,553],{"class":541},[535,580,557],{"class":556},[535,582,583],{"class":541},">\u003C\u002F",[535,585,573],{"class":545},[535,587,565],{"class":541},[535,589,591,593,596,598,600,603,605,607],{"class":537,"line":590},3,[535,592,542],{"class":541},[535,594,595],{"class":545},"div",[535,597,576],{"class":549},[535,599,553],{"class":541},[535,601,602],{"class":556},"\"answer\"",[535,604,583],{"class":541},[535,606,595],{"class":545},[535,608,565],{"class":541},[19,610,614],{"className":611,"code":612,"language":613,"meta":28,"style":28},"language-css shiki shiki-themes github-light github-dark","label { display: block; margin-bottom: 6px; font-weight: 600; }\nselect { font: inherit; padding: 6px 8px; width: 100%; max-width: 420px; }\n#answer { margin-top: 14px; padding: 14px; border-radius: 10px; background: #fffbeb; border: 1px solid #fcd34d; }\n#answer strong { display: block; font: 700 22px ui-monospace, monospace; color: #b45309; margin-bottom: 4px; }\n","css",[26,615,616,661,718,787],{"__ignoreMap":28},[535,617,618,620,623,627,630,633,636,639,641,644,648,650,653,655,658],{"class":537,"line":538},[535,619,546],{"class":545},[535,621,622],{"class":541}," { ",[535,624,626],{"class":625},"sj4cs","display",[535,628,629],{"class":541},": ",[535,631,632],{"class":625},"block",[535,634,635],{"class":541},"; ",[535,637,638],{"class":625},"margin-bottom",[535,640,629],{"class":541},[535,642,643],{"class":625},"6",[535,645,647],{"class":646},"szBVR","px",[535,649,635],{"class":541},[535,651,652],{"class":625},"font-weight",[535,654,629],{"class":541},[535,656,657],{"class":625},"600",[535,659,660],{"class":541},"; }\n",[535,662,663,665,667,670,672,675,677,680,682,684,686,689,691,693,696,698,701,704,706,709,711,714,716],{"class":537,"line":568},[535,664,573],{"class":545},[535,666,622],{"class":541},[535,668,669],{"class":625},"font",[535,671,629],{"class":541},[535,673,674],{"class":625},"inherit",[535,676,635],{"class":541},[535,678,679],{"class":625},"padding",[535,681,629],{"class":541},[535,683,643],{"class":625},[535,685,647],{"class":646},[535,687,688],{"class":625}," 8",[535,690,647],{"class":646},[535,692,635],{"class":541},[535,694,695],{"class":625},"width",[535,697,629],{"class":541},[535,699,700],{"class":625},"100",[535,702,703],{"class":646},"%",[535,705,635],{"class":541},[535,707,708],{"class":625},"max-width",[535,710,629],{"class":541},[535,712,713],{"class":625},"420",[535,715,647],{"class":646},[535,717,660],{"class":541},[535,719,720,723,725,728,730,733,735,737,739,741,743,745,747,750,752,755,757,759,762,764,767,769,772,774,777,779,782,785],{"class":537,"line":590},[535,721,722],{"class":549},"#answer",[535,724,622],{"class":541},[535,726,727],{"class":625},"margin-top",[535,729,629],{"class":541},[535,731,732],{"class":625},"14",[535,734,647],{"class":646},[535,736,635],{"class":541},[535,738,679],{"class":625},[535,740,629],{"class":541},[535,742,732],{"class":625},[535,744,647],{"class":646},[535,746,635],{"class":541},[535,748,749],{"class":625},"border-radius",[535,751,629],{"class":541},[535,753,754],{"class":625},"10",[535,756,647],{"class":646},[535,758,635],{"class":541},[535,760,761],{"class":625},"background",[535,763,629],{"class":541},[535,765,766],{"class":625},"#fffbeb",[535,768,635],{"class":541},[535,770,771],{"class":625},"border",[535,773,629],{"class":541},[535,775,776],{"class":625},"1",[535,778,647],{"class":646},[535,780,781],{"class":625}," solid",[535,783,784],{"class":625}," #fcd34d",[535,786,660],{"class":541},[535,788,790,792,795,797,799,801,803,805,807,809,812,815,817,820,823,826,828,831,833,836,838,840,842,845,847],{"class":537,"line":789},4,[535,791,722],{"class":549},[535,793,794],{"class":545}," strong",[535,796,622],{"class":541},[535,798,626],{"class":625},[535,800,629],{"class":541},[535,802,632],{"class":625},[535,804,635],{"class":541},[535,806,669],{"class":625},[535,808,629],{"class":541},[535,810,811],{"class":625},"700",[535,813,814],{"class":625}," 22",[535,816,647],{"class":646},[535,818,819],{"class":625}," ui-monospace",[535,821,822],{"class":541},", ",[535,824,825],{"class":625},"monospace",[535,827,635],{"class":541},[535,829,830],{"class":625},"color",[535,832,629],{"class":541},[535,834,835],{"class":625},"#b45309",[535,837,635],{"class":541},[535,839,638],{"class":625},[535,841,629],{"class":541},[535,843,844],{"class":625},"4",[535,846,647],{"class":646},[535,848,660],{"class":541},[19,850,854],{"className":851,"code":852,"language":853,"meta":28,"style":28},"language-js shiki shiki-themes github-light github-dark","const cases = [\n  [\"Fetched a list of posts\", \"200 OK\", \"Regular success. Put the list in the body.\"],\n  [\"Created a new account at sign-up\", \"201 Created\", \"New resource created. Put its URL in the Location header.\"],\n  [\"Deleted a post, nothing to return\", \"204 No Content\", \"Success with no body. The frontend must not call res.json().\"],\n  [\"The request body's JSON syntax is broken\", \"400 Bad Request\", \"The request can't be parsed at all.\"],\n  [\"The email format is invalid\", \"422 Unprocessable Content\", \"The format is fine but the content fails validation. (400 on some teams)\"],\n  [\"The login token expired\", \"401 Unauthorized\", \"We can't tell who you are. Log in again or refresh the token.\"],\n  [\"A regular user called an admin API\", \"403 Forbidden\", \"We know who you are, but you lack permission. Logging in again won't help.\"],\n  [\"Requested someone else's private post\", \"404 Not Found\", \"Use 404 instead of 403 to hide that it exists.\"],\n  [\"Signing up with an email that's already registered\", \"409 Conflict\", \"Conflicts with the server's current state.\"],\n  [\"Tried to log in 100 times in a minute\", \"429 Too Many Requests\", \"Rate limit exceeded. Use Retry-After to say when to try again.\"],\n  [\"An exception was thrown in server code\", \"500 Internal Server Error\", \"The server's fault. Don't use it for bad user input.\"],\n  [\"The upstream payment server isn't responding\", \"504 Gateway Timeout\", \"A middle server timed out waiting for the upstream server.\"],\n  [\"The service is temporarily down for maintenance\", \"503 Service Unavailable\", \"Temporarily unable to handle requests. Sending Retry-After helps.\"],\n];\n\nconst select = document.querySelector(\"#situation\");\nconst answer = document.querySelector(\"#answer\");\ncases.forEach(([s], i) => select.add(new Option(s, i)));\nconst show = () => {\n  const [, code, why] = cases[select.value];\n  answer.innerHTML = `\u003Cstrong>${code}\u003C\u002Fstrong>${why}`;\n};\nselect.addEventListener(\"change\", show);\nshow();\n","js",[26,855,856,870,891,910,929,949,969,989,1009,1029,1049,1069,1089,1109,1129,1135,1142,1167,1188,1233,1251,1275,1299,1305,1322],{"__ignoreMap":28},[535,857,858,861,864,867],{"class":537,"line":538},[535,859,860],{"class":646},"const",[535,862,863],{"class":625}," cases",[535,865,866],{"class":646}," =",[535,868,869],{"class":541}," [\n",[535,871,872,875,878,880,883,885,888],{"class":537,"line":568},[535,873,874],{"class":541},"  [",[535,876,877],{"class":556},"\"Fetched a list of posts\"",[535,879,822],{"class":541},[535,881,882],{"class":556},"\"200 OK\"",[535,884,822],{"class":541},[535,886,887],{"class":556},"\"Regular success. Put the list in the body.\"",[535,889,890],{"class":541},"],\n",[535,892,893,895,898,900,903,905,908],{"class":537,"line":590},[535,894,874],{"class":541},[535,896,897],{"class":556},"\"Created a new account at sign-up\"",[535,899,822],{"class":541},[535,901,902],{"class":556},"\"201 Created\"",[535,904,822],{"class":541},[535,906,907],{"class":556},"\"New resource created. Put its URL in the Location header.\"",[535,909,890],{"class":541},[535,911,912,914,917,919,922,924,927],{"class":537,"line":789},[535,913,874],{"class":541},[535,915,916],{"class":556},"\"Deleted a post, nothing to return\"",[535,918,822],{"class":541},[535,920,921],{"class":556},"\"204 No Content\"",[535,923,822],{"class":541},[535,925,926],{"class":556},"\"Success with no body. The frontend must not call res.json().\"",[535,928,890],{"class":541},[535,930,932,934,937,939,942,944,947],{"class":537,"line":931},5,[535,933,874],{"class":541},[535,935,936],{"class":556},"\"The request body's JSON syntax is broken\"",[535,938,822],{"class":541},[535,940,941],{"class":556},"\"400 Bad Request\"",[535,943,822],{"class":541},[535,945,946],{"class":556},"\"The request can't be parsed at all.\"",[535,948,890],{"class":541},[535,950,952,954,957,959,962,964,967],{"class":537,"line":951},6,[535,953,874],{"class":541},[535,955,956],{"class":556},"\"The email format is invalid\"",[535,958,822],{"class":541},[535,960,961],{"class":556},"\"422 Unprocessable Content\"",[535,963,822],{"class":541},[535,965,966],{"class":556},"\"The format is fine but the content fails validation. (400 on some teams)\"",[535,968,890],{"class":541},[535,970,972,974,977,979,982,984,987],{"class":537,"line":971},7,[535,973,874],{"class":541},[535,975,976],{"class":556},"\"The login token expired\"",[535,978,822],{"class":541},[535,980,981],{"class":556},"\"401 Unauthorized\"",[535,983,822],{"class":541},[535,985,986],{"class":556},"\"We can't tell who you are. Log in again or refresh the token.\"",[535,988,890],{"class":541},[535,990,992,994,997,999,1002,1004,1007],{"class":537,"line":991},8,[535,993,874],{"class":541},[535,995,996],{"class":556},"\"A regular user called an admin API\"",[535,998,822],{"class":541},[535,1000,1001],{"class":556},"\"403 Forbidden\"",[535,1003,822],{"class":541},[535,1005,1006],{"class":556},"\"We know who you are, but you lack permission. Logging in again won't help.\"",[535,1008,890],{"class":541},[535,1010,1012,1014,1017,1019,1022,1024,1027],{"class":537,"line":1011},9,[535,1013,874],{"class":541},[535,1015,1016],{"class":556},"\"Requested someone else's private post\"",[535,1018,822],{"class":541},[535,1020,1021],{"class":556},"\"404 Not Found\"",[535,1023,822],{"class":541},[535,1025,1026],{"class":556},"\"Use 404 instead of 403 to hide that it exists.\"",[535,1028,890],{"class":541},[535,1030,1032,1034,1037,1039,1042,1044,1047],{"class":537,"line":1031},10,[535,1033,874],{"class":541},[535,1035,1036],{"class":556},"\"Signing up with an email that's already registered\"",[535,1038,822],{"class":541},[535,1040,1041],{"class":556},"\"409 Conflict\"",[535,1043,822],{"class":541},[535,1045,1046],{"class":556},"\"Conflicts with the server's current state.\"",[535,1048,890],{"class":541},[535,1050,1052,1054,1057,1059,1062,1064,1067],{"class":537,"line":1051},11,[535,1053,874],{"class":541},[535,1055,1056],{"class":556},"\"Tried to log in 100 times in a minute\"",[535,1058,822],{"class":541},[535,1060,1061],{"class":556},"\"429 Too Many Requests\"",[535,1063,822],{"class":541},[535,1065,1066],{"class":556},"\"Rate limit exceeded. Use Retry-After to say when to try again.\"",[535,1068,890],{"class":541},[535,1070,1072,1074,1077,1079,1082,1084,1087],{"class":537,"line":1071},12,[535,1073,874],{"class":541},[535,1075,1076],{"class":556},"\"An exception was thrown in server code\"",[535,1078,822],{"class":541},[535,1080,1081],{"class":556},"\"500 Internal Server Error\"",[535,1083,822],{"class":541},[535,1085,1086],{"class":556},"\"The server's fault. Don't use it for bad user input.\"",[535,1088,890],{"class":541},[535,1090,1092,1094,1097,1099,1102,1104,1107],{"class":537,"line":1091},13,[535,1093,874],{"class":541},[535,1095,1096],{"class":556},"\"The upstream payment server isn't responding\"",[535,1098,822],{"class":541},[535,1100,1101],{"class":556},"\"504 Gateway Timeout\"",[535,1103,822],{"class":541},[535,1105,1106],{"class":556},"\"A middle server timed out waiting for the upstream server.\"",[535,1108,890],{"class":541},[535,1110,1112,1114,1117,1119,1122,1124,1127],{"class":537,"line":1111},14,[535,1113,874],{"class":541},[535,1115,1116],{"class":556},"\"The service is temporarily down for maintenance\"",[535,1118,822],{"class":541},[535,1120,1121],{"class":556},"\"503 Service Unavailable\"",[535,1123,822],{"class":541},[535,1125,1126],{"class":556},"\"Temporarily unable to handle requests. Sending Retry-After helps.\"",[535,1128,890],{"class":541},[535,1130,1132],{"class":537,"line":1131},15,[535,1133,1134],{"class":541},"];\n",[535,1136,1138],{"class":537,"line":1137},16,[535,1139,1141],{"emptyLinePlaceholder":1140},true,"\n",[535,1143,1145,1147,1150,1152,1155,1158,1161,1164],{"class":537,"line":1144},17,[535,1146,860],{"class":646},[535,1148,1149],{"class":625}," select",[535,1151,866],{"class":646},[535,1153,1154],{"class":541}," document.",[535,1156,1157],{"class":549},"querySelector",[535,1159,1160],{"class":541},"(",[535,1162,1163],{"class":556},"\"#situation\"",[535,1165,1166],{"class":541},");\n",[535,1168,1170,1172,1175,1177,1179,1181,1183,1186],{"class":537,"line":1169},18,[535,1171,860],{"class":646},[535,1173,1174],{"class":625}," answer",[535,1176,866],{"class":646},[535,1178,1154],{"class":541},[535,1180,1157],{"class":549},[535,1182,1160],{"class":541},[535,1184,1185],{"class":556},"\"#answer\"",[535,1187,1166],{"class":541},[535,1189,1191,1194,1197,1200,1204,1207,1210,1213,1216,1219,1222,1224,1227,1230],{"class":537,"line":1190},19,[535,1192,1193],{"class":541},"cases.",[535,1195,1196],{"class":549},"forEach",[535,1198,1199],{"class":541},"(([",[535,1201,1203],{"class":1202},"s4XuR","s",[535,1205,1206],{"class":541},"], ",[535,1208,1209],{"class":1202},"i",[535,1211,1212],{"class":541},") ",[535,1214,1215],{"class":646},"=>",[535,1217,1218],{"class":541}," select.",[535,1220,1221],{"class":549},"add",[535,1223,1160],{"class":541},[535,1225,1226],{"class":646},"new",[535,1228,1229],{"class":549}," Option",[535,1231,1232],{"class":541},"(s, i)));\n",[535,1234,1236,1238,1241,1243,1246,1248],{"class":537,"line":1235},20,[535,1237,860],{"class":646},[535,1239,1240],{"class":549}," show",[535,1242,866],{"class":646},[535,1244,1245],{"class":541}," () ",[535,1247,1215],{"class":646},[535,1249,1250],{"class":541}," {\n",[535,1252,1254,1257,1260,1262,1264,1267,1270,1272],{"class":537,"line":1253},21,[535,1255,1256],{"class":646},"  const",[535,1258,1259],{"class":541}," [, ",[535,1261,26],{"class":625},[535,1263,822],{"class":541},[535,1265,1266],{"class":625},"why",[535,1268,1269],{"class":541},"] ",[535,1271,553],{"class":646},[535,1273,1274],{"class":541}," cases[select.value];\n",[535,1276,1278,1281,1283,1286,1288,1291,1293,1296],{"class":537,"line":1277},22,[535,1279,1280],{"class":541},"  answer.innerHTML ",[535,1282,553],{"class":646},[535,1284,1285],{"class":556}," `\u003Cstrong>${",[535,1287,26],{"class":541},[535,1289,1290],{"class":556},"}\u003C\u002Fstrong>${",[535,1292,1266],{"class":541},[535,1294,1295],{"class":556},"}`",[535,1297,1298],{"class":541},";\n",[535,1300,1302],{"class":537,"line":1301},23,[535,1303,1304],{"class":541},"};\n",[535,1306,1308,1311,1314,1316,1319],{"class":537,"line":1307},24,[535,1309,1310],{"class":541},"select.",[535,1312,1313],{"class":549},"addEventListener",[535,1315,1160],{"class":541},[535,1317,1318],{"class":556},"\"change\"",[535,1320,1321],{"class":541},", show);\n",[535,1323,1325,1328],{"class":537,"line":1324},25,[535,1326,1327],{"class":549},"show",[535,1329,1330],{"class":541},"();\n",[73,1332],{},[10,1334,1336],{"id":1335},"_5xx-server-failures-come-in-kinds-too","5xx: server failures come in kinds too",[80,1338,1339,1349],{},[83,1340,1341],{},[86,1342,1343,1345,1347],{},[89,1344,192],{},[89,1346,94],{},[89,1348,198],{},[99,1350,1351,1364,1381,1398],{},[86,1352,1353,1358,1361],{},[104,1354,1355],{},[26,1356,1357],{},"500 Internal Server Error",[104,1359,1360],{},"Unexpected error in server code",[104,1362,1363],{},"An unhandled exception",[86,1365,1366,1371,1378],{},[104,1367,1368],{},[26,1369,1370],{},"502 Bad Gateway",[104,1372,1373,1374,1377],{},"A middle server (proxy, gateway) got an ",[68,1375,1376],{},"invalid response"," from the upstream server",[104,1379,1380],{},"The upstream app server crashed and the connection dropped",[86,1382,1383,1388,1395],{},[104,1384,1385],{},[26,1386,1387],{},"503 Service Unavailable",[104,1389,1390,1391,1394],{},"The server ",[68,1392,1393],{},"temporarily"," can't handle requests",[104,1396,1397],{},"Maintenance, overload",[86,1399,1400,1405,1412],{},[104,1401,1402],{},[26,1403,1404],{},"504 Gateway Timeout",[104,1406,1407,1408,1411],{},"A middle server ",[68,1409,1410],{},"timed out waiting"," for the upstream server",[104,1413,1414],{},"A slow DB query kept the app server from responding",[15,1416,1417,1418,1421,1422,1425],{},"You usually don't send ",[26,1419,1420],{},"502"," or ",[26,1423,1424],{},"504"," yourself; middle servers like Nginx or a load balancer return them for you. When you see them, suspect the link \"between the front proxy and the app server.\"",[1427,1428,1429],"tip",{},[62,1430,1431],{},[15,1432,1433,1434,1436],{},"Don't put stack traces or DB queries in the body of a ",[26,1435,176],{}," response. That hands attackers a map of your internals. Log the details on the server and return something like a trace ID in the response.",[73,1438],{},[10,1440,1442],{"id":1441},"the-3xx-trap-redirects-that-turn-post-into-get","The 3xx trap: redirects that turn POST into GET",[15,1444,1445,1446,1449,1450,1453,1454,1457],{},"Redirect codes don't just differ in \"where to go\"; they differ in ",[68,1447,1448],{},"whether the original method is kept",". Redirecting a real ",[26,1451,1452],{},"POST"," request (body ",[26,1455,1456],{},"name=kim",") with each code gives:",[80,1459,1460,1471],{},[83,1461,1462],{},[86,1463,1464,1466,1468],{},[89,1465,192],{},[89,1467,94],{},[89,1469,1470],{},"Request after the redirect",[99,1472,1473,1491,1507,1525,1540],{},[86,1474,1475,1480,1483],{},[104,1476,1477],{},[26,1478,1479],{},"301 Moved Permanently",[104,1481,1482],{},"Moved permanently",[104,1484,1485],{},[68,1486,1487,1490],{},[26,1488,1489],{},"GET",", body dropped",[86,1492,1493,1498,1501],{},[104,1494,1495],{},[26,1496,1497],{},"302 Found",[104,1499,1500],{},"Moved temporarily",[104,1502,1503],{},[68,1504,1505,1490],{},[26,1506,1489],{},[86,1508,1509,1514,1520],{},[104,1510,1511],{},[26,1512,1513],{},"303 See Other",[104,1515,1516,1517,1519],{},"Go ",[26,1518,1489],{}," something else",[104,1521,1522,1524],{},[26,1523,1489],{}," (intended)",[86,1526,1527,1532,1535],{},[104,1528,1529],{},[26,1530,1531],{},"307 Temporary Redirect",[104,1533,1534],{},"Moved temporarily, method kept",[104,1536,1537,1539],{},[26,1538,1452],{},", body kept",[86,1541,1542,1547,1550],{},[104,1543,1544],{},[26,1545,1546],{},"308 Permanent Redirect",[104,1548,1549],{},"Moved permanently, method kept",[104,1551,1552,1539],{},[26,1553,1452],{},[15,1555,1556,1557,1559,1560,1562,1563,1566,1567,1570,1571,1573,1574,1576],{},"For historical reasons, browsers turn ",[26,1558,1452],{}," into ",[26,1561,1489],{}," on ",[26,1564,1565],{},"301"," and ",[26,1568,1569],{},"302",". So if you move an API endpoint and put a ",[26,1572,1565],{}," on the old URL, ",[26,1575,1452],{}," bodies silently disappear.",[33,1578,1579,1587,1597],{},[36,1580,1581,1582,1421,1584],{},"Moving page URLs (SEO): ",[26,1583,1565],{},[26,1585,1586],{},"308",[36,1588,1589,1590,1592,1593,1596],{},"Moving API endpoints: ",[26,1591,1586],{},", which keeps the method and body (",[26,1594,1595],{},"307"," if temporary)",[36,1598,1599,1600],{},"Sending the user to a result page after a form submit (to prevent resubmission on refresh): ",[26,1601,1602],{},"303",[73,1604],{},[10,1606,1608],{"id":1607},"summary-why-this-is-worth-knowing","Summary: why this is worth knowing",[80,1610,1611,1621],{},[83,1612,1613],{},[86,1614,1615,1618],{},[89,1616,1617],{},"Situation",[89,1619,1620],{},"Status code",[99,1622,1623,1633,1645,1654,1663,1676,1685,1698,1708,1719,1728,1738],{},[86,1624,1625,1628],{},[104,1626,1627],{},"Successful read",[104,1629,1630],{},[26,1631,1632],{},"200",[86,1634,1635,1638],{},[104,1636,1637],{},"Successful create",[104,1639,1640,1642,1643],{},[26,1641,252],{}," + ",[26,1644,256],{},[86,1646,1647,1650],{},[104,1648,1649],{},"Success, no body",[104,1651,1652],{},[26,1653,274],{},[86,1655,1656,1659],{},[104,1657,1658],{},"Malformed request",[104,1660,1661],{},[26,1662,353],{},[86,1664,1665,1668],{},[104,1666,1667],{},"Validation failure",[104,1669,1670,1673,1674,520],{},[26,1671,1672],{},"422"," (or consistently ",[26,1675,353],{},[86,1677,1678,1681],{},[104,1679,1680],{},"Login required \u002F token expired",[104,1682,1683],{},[26,1684,417],{},[86,1686,1687,1690],{},[104,1688,1689],{},"No permission",[104,1691,1692,1694,1695,1697],{},[26,1693,436],{}," (",[26,1696,432],{}," to hide existence)",[86,1699,1700,1703],{},[104,1701,1702],{},"Duplicate, state conflict",[104,1704,1705],{},[26,1706,1707],{},"409",[86,1709,1710,1712],{},[104,1711,513],{},[104,1713,1714,1642,1717],{},[26,1715,1716],{},"429",[26,1718,519],{},[86,1720,1721,1724],{},[104,1722,1723],{},"Server exception",[104,1725,1726],{},[26,1727,176],{},[86,1729,1730,1733],{},[104,1731,1732],{},"Temporary maintenance, overload",[104,1734,1735],{},[26,1736,1737],{},"503",[86,1739,1740,1743],{},[104,1741,1742],{},"Moving an API endpoint",[104,1744,1745,1694,1747,1749,1750,1559,1752,520],{},[26,1746,1586],{},[26,1748,1565],{}," turns ",[26,1751,1452],{},[26,1753,1489],{},[15,1755,1756,1757,1760,1761,1764,1765,54],{},"Use status codes properly and ",[68,1758,1759],{},"clients can decide what to do before opening the body"," (log in again, retry, fix the input), and monitoring tools count failures as failures. What the error ",[68,1762,1763],{},"body"," should look like is covered next, in ",[1766,1767,1769],"a",{"href":1768},"\u002Fen\u002Fapi-error-response-format","designing API error responses",[1771,1772,1773],"style",{},"html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}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);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}",{"title":28,"searchDepth":568,"depth":568,"links":1775},[1776,1777,1778,1779,1785,1786,1787],{"id":12,"depth":568,"text":13},{"id":77,"depth":568,"text":78},{"id":182,"depth":568,"text":183},{"id":295,"depth":568,"text":296,"children":1780},[1781,1782,1783,1784],{"id":300,"depth":590,"text":301},{"id":360,"depth":590,"text":361},{"id":421,"depth":590,"text":422},{"id":446,"depth":590,"text":447},{"id":1335,"depth":568,"text":1336},{"id":1441,"depth":568,"text":1442},{"id":1607,"depth":568,"text":1608},"If your errors come back as 200 with success: false, clients and monitoring tools can't tell anything failed. Which status code fits which situation, the difference between easily confused codes like 401 and 403 or 400 and 422, and the redirect trap where 301 turns POST into GET.","md",{"date":1791,"field":1792,"tags":1793},"2026.10.08","backend",[1794,1795],"http","api","\u002Fen\u002Fhttp-status-codes-guide",{"title":5,"description":1788},{"loc":1796},"en\u002Fhttp-status-codes-guide","tCLBJgobggzRWbMHgvEzr8LK_AOqe-BoEieSBwlwk38",1791482015983]