[{"data":1,"prerenderedAt":1099},["ShallowReactive",2],{"page:\u002Fextensions\u002Fkubb-labs\u002Fplugin-fetch\u002Fguides\u002Ferror-handling":3},{"id":4,"frontmatter":5,"title":6,"heading":6,"body":7,"path":1098,"source":4},"extensions\u002Fkubb-labs\u002Fplugin-fetch\u002Fguides\u002Ferror-handling.md",{},"Handle errors",{"type":8,"value":9,"toc":1090},"minimark",[10,23,29,265,275,278,427,445,450,469,618,622,632,756,762,766,785,897,903,907,920,1057,1069],[11,12,13,14,18,19,22],"p",{},"Handle failures from the client Kubb generates. Catch a ",[15,16,17],"code",{},"ResponseError",", switch to a returned error result with ",[15,20,21],{},"throwOnError",", and tell a network failure apart from a 4xx or 5xx response.",[11,24,25,26,28],{},"The generated client throws a ",[15,27,17],{}," on non-2xx responses by default:",[30,31,35],"pre",{"language":32,"code":33,"class":34},"typescript","import { getPetById } from '.\u002Fgen\u002Fclients\u002FgetPetById'\nimport { ResponseError } from '.\u002Fgen\u002F.kubb\u002Fclient'\n\ntry {\n  const { data } = await getPetById({ path: { petId: 1 } })\n  console.info(data.name)\n} catch (error) {\n  if (ResponseError.is(error)) {\n    console.error(error.status) \u002F\u002F 404\n    console.error(error.data) \u002F\u002F the parsed error body\n  }\n}","highlights",[15,36,38,65,66,65,83,65,85,65,93,65,139,65,166,65,181,65,204,65,231,65,254,65,261],{"class":37},"language-typescript",[39,40,43,47,51,55,58,61],"span",{"class":41,"style":42},"line","display: inline",[39,44,46],{"style":45},"color:#d73a49;--hls-dark:#f97583","import ",[39,48,50],{"style":49},"color:#005cc5;--hls-dark:#79b8ff","{ ",[39,52,54],{"style":53},"color:#24292e;--hls-dark:#e1e4e8","getPetById ",[39,56,57],{"style":49},"} ",[39,59,60],{"style":45},"from ",[39,62,64],{"style":63},"color:#032f62;--hls-dark:#9ecbff","'.\u002Fgen\u002Fclients\u002FgetPetById'","\n",[39,67,68,70,72,76,78,80],{"class":41,"style":42},[39,69,46],{"style":45},[39,71,50],{"style":49},[39,73,75],{"style":74},"color:#6f42c1;--hls-dark:#b392f0","ResponseError ",[39,77,57],{"style":49},[39,79,60],{"style":45},[39,81,82],{"style":63},"'.\u002Fgen\u002F.kubb\u002Fclient'",[39,84],{"class":41,"style":42},[39,86,87,90],{"class":41,"style":42},[39,88,89],{"style":45},"try ",[39,91,92],{"style":49},"{",[39,94,95,98,101,103,106,108,111,114,117,120,123,126,128,131,133,136],{"class":41,"style":42},[39,96,97],{"style":49},"  ",[39,99,100],{"style":45},"const ",[39,102,50],{"style":49},[39,104,105],{"style":53},"data ",[39,107,57],{"style":49},[39,109,110],{"style":45},"= ",[39,112,113],{"style":45},"await ",[39,115,116],{"style":74},"getPetById",[39,118,119],{"style":49},"({ ",[39,121,122],{"style":49},"path",[39,124,125],{"style":45},": ",[39,127,50],{"style":49},[39,129,130],{"style":49},"petId",[39,132,125],{"style":45},[39,134,135],{"style":49},"1 ",[39,137,138],{"style":49},"} })",[39,140,141,143,146,149,152,155,158,160,163],{"class":41,"style":42},[39,142,97],{"style":49},[39,144,145],{"style":53},"console",[39,147,148],{"style":45},".",[39,150,151],{"style":74},"info",[39,153,154],{"style":49},"(",[39,156,157],{"style":53},"data",[39,159,148],{"style":45},[39,161,162],{"style":49},"name",[39,164,165],{"style":49},")",[39,167,168,170,173,175,178],{"class":41,"style":42},[39,169,57],{"style":49},[39,171,172],{"style":45},"catch ",[39,174,154],{"style":49},[39,176,177],{"style":53},"error",[39,179,180],{"style":49},") {",[39,182,183,185,188,190,192,194,197,199,201],{"class":41,"style":42},[39,184,97],{"style":49},[39,186,187],{"style":45},"if ",[39,189,154],{"style":49},[39,191,17],{"style":74},[39,193,148],{"style":45},[39,195,196],{"style":74},"is",[39,198,154],{"style":49},[39,200,177],{"style":53},[39,202,203],{"style":49},")) {",[39,205,206,209,211,213,215,217,219,221,224,227],{"class":41,"style":42},[39,207,208],{"style":49},"    ",[39,210,145],{"style":53},[39,212,148],{"style":45},[39,214,177],{"style":74},[39,216,154],{"style":49},[39,218,177],{"style":53},[39,220,148],{"style":45},[39,222,223],{"style":49},"status",[39,225,226],{"style":49},") ",[39,228,230],{"style":229},"color:#6a737d;--hls-dark:#6a737d","\u002F\u002F 404",[39,232,233,235,237,239,241,243,245,247,249,251],{"class":41,"style":42},[39,234,208],{"style":229},[39,236,145],{"style":53},[39,238,148],{"style":45},[39,240,177],{"style":74},[39,242,154],{"style":49},[39,244,177],{"style":53},[39,246,148],{"style":45},[39,248,157],{"style":49},[39,250,226],{"style":49},[39,252,253],{"style":229},"\u002F\u002F the parsed error body",[39,255,256,258],{"class":41,"style":42},[39,257,97],{"style":229},[39,259,260],{"style":49},"}",[39,262,263],{"class":41,"style":42},[39,264,260],{"style":49},[11,266,267,268,271,272,148],{},"The ",[15,269,270],{},"message"," holds the HTTP method and the URL without its query string, so query credentials stay out of logs. For example: ",[15,273,274],{},"GET https:\u002F\u002Fapi.example.com\u002Fpets\u002F1 failed with status 404 Not Found",[11,276,277],{},"The error exposes these fields:",[30,279,281],{"language":32,"code":280,"class":34},"class ResponseError extends Error {\n  static is(error: unknown): error is ResponseError\u003Cunknown, unknown, unknown>\n  data: TError \u002F\u002F the parsed error body\n  status: number\n  statusText: string\n  contentType: string | undefined\n  request: Request\n  response: Response\n}",[15,282,283,65,298,65,345,65,358,65,369,65,381,65,399,65,411,65,423],{"class":37},[39,284,285,288,290,293,296],{"class":41,"style":42},[39,286,287],{"style":45},"class ",[39,289,75],{"style":74},[39,291,292],{"style":45},"extends ",[39,294,295],{"style":74},"Error ",[39,297,92],{"style":49},[39,299,300,302,305,307,309,311,313,316,318,320,323,326,328,331,333,336,338,340,342],{"class":41,"style":42},[39,301,97],{"style":49},[39,303,304],{"style":45},"static ",[39,306,196],{"style":74},[39,308,154],{"style":49},[39,310,177],{"style":53},[39,312,125],{"style":53},[39,314,315],{"style":74},"unknown",[39,317,165],{"style":49},[39,319,125],{"style":45},[39,321,322],{"style":53},"error ",[39,324,325],{"style":45},"is ",[39,327,17],{"style":74},[39,329,330],{"style":45},"\u003C",[39,332,315],{"style":53},[39,334,335],{"style":45},", ",[39,337,315],{"style":53},[39,339,335],{"style":45},[39,341,315],{"style":53},[39,343,344],{"style":45},">",[39,346,347,349,351,353,356],{"class":41,"style":42},[39,348,97],{"style":45},[39,350,157],{"style":53},[39,352,125],{"style":53},[39,354,355],{"style":74},"TError ",[39,357,253],{"style":229},[39,359,360,362,364,366],{"class":41,"style":42},[39,361,97],{"style":229},[39,363,223],{"style":53},[39,365,125],{"style":53},[39,367,368],{"style":74},"number",[39,370,371,373,376,378],{"class":41,"style":42},[39,372,97],{"style":74},[39,374,375],{"style":53},"statusText",[39,377,125],{"style":53},[39,379,380],{"style":74},"string",[39,382,383,385,388,390,393,396],{"class":41,"style":42},[39,384,97],{"style":74},[39,386,387],{"style":53},"contentType",[39,389,125],{"style":53},[39,391,392],{"style":74},"string ",[39,394,395],{"style":45},"| ",[39,397,398],{"style":49},"undefined",[39,400,401,403,406,408],{"class":41,"style":42},[39,402,97],{"style":49},[39,404,405],{"style":53},"request",[39,407,125],{"style":53},[39,409,410],{"style":74},"Request",[39,412,413,415,418,420],{"class":41,"style":42},[39,414,97],{"style":74},[39,416,417],{"style":53},"response",[39,419,125],{"style":53},[39,421,422],{"style":74},"Response",[39,424,425],{"class":41,"style":42},[39,426,260],{"style":49},[11,428,429,430,432,433,436,437,440,441,444],{},"Each generated package bundles its own ",[15,431,17],{}," class, so narrow with ",[15,434,435],{},"ResponseError.is(error)"," instead of ",[15,438,439],{},"instanceof",". ",[15,442,443],{},"is()"," checks the error name.",[446,447,449],"h2",{"id":448},"return-the-error-instead","Return the error instead",[11,451,452,453,456,457,459,460,462,463,465,466,468],{},"Pass ",[15,454,455],{},"throwOnError: false"," and the call resolves for every documented status. The result is a\ndiscriminated union: ",[15,458,157],{}," is set on success and ",[15,461,177],{}," on failure. Branch on ",[15,464,223],{},",\nbecause an empty error body can leave ",[15,467,177],{}," empty or undefined.",[30,470,472],{"language":32,"code":471,"class":34},"const result = await getPetById({ path: { petId: 1 }, throwOnError: false })\n\nif (result.status === 200) {\n  console.info(result.data.name)\n}\nif (result.status !== 200) {\n  console.error(result.status, result.error)\n}",[15,473,474,65,515,65,517,65,539,65,563,65,567,65,586,65,614],{"class":37},[39,475,476,478,481,483,485,487,489,491,493,495,497,499,501,503,505,507,509,512],{"class":41,"style":42},[39,477,100],{"style":45},[39,479,480],{"style":53},"result ",[39,482,110],{"style":45},[39,484,113],{"style":45},[39,486,116],{"style":74},[39,488,119],{"style":49},[39,490,122],{"style":49},[39,492,125],{"style":45},[39,494,50],{"style":49},[39,496,130],{"style":49},[39,498,125],{"style":45},[39,500,135],{"style":49},[39,502,260],{"style":49},[39,504,335],{"style":45},[39,506,21],{"style":49},[39,508,125],{"style":45},[39,510,511],{"style":49},"false ",[39,513,514],{"style":49},"})",[39,516],{"class":41,"style":42},[39,518,519,521,523,526,528,531,534,537],{"class":41,"style":42},[39,520,187],{"style":45},[39,522,154],{"style":49},[39,524,525],{"style":53},"result",[39,527,148],{"style":45},[39,529,530],{"style":49},"status ",[39,532,533],{"style":45},"=== ",[39,535,536],{"style":49},"200",[39,538,180],{"style":49},[39,540,541,543,545,547,549,551,553,555,557,559,561],{"class":41,"style":42},[39,542,97],{"style":49},[39,544,145],{"style":53},[39,546,148],{"style":45},[39,548,151],{"style":74},[39,550,154],{"style":49},[39,552,525],{"style":53},[39,554,148],{"style":45},[39,556,157],{"style":49},[39,558,148],{"style":45},[39,560,162],{"style":49},[39,562,165],{"style":49},[39,564,565],{"class":41,"style":42},[39,566,260],{"style":49},[39,568,569,571,573,575,577,579,582,584],{"class":41,"style":42},[39,570,187],{"style":45},[39,572,154],{"style":49},[39,574,525],{"style":53},[39,576,148],{"style":45},[39,578,530],{"style":49},[39,580,581],{"style":45},"!== ",[39,583,536],{"style":49},[39,585,180],{"style":49},[39,587,588,590,592,594,596,598,600,602,604,606,608,610,612],{"class":41,"style":42},[39,589,97],{"style":49},[39,591,145],{"style":53},[39,593,148],{"style":45},[39,595,177],{"style":74},[39,597,154],{"style":49},[39,599,525],{"style":53},[39,601,148],{"style":45},[39,603,223],{"style":49},[39,605,335],{"style":45},[39,607,525],{"style":53},[39,609,148],{"style":45},[39,611,177],{"style":49},[39,613,165],{"style":49},[39,615,616],{"class":41,"style":42},[39,617,260],{"style":49},[446,619,621],{"id":620},"set-the-generated-default","Set the generated default",[11,623,624,625,628,629,631],{},"Set ",[15,626,627],{},"throwOnErrorDefault"," on the client plugin to choose how generated operations handle non-2xx\nresponses by default. Each call can still override that setting with ",[15,630,21],{},":",[30,633,635],{"language":32,"code":634,"class":34},"import { pluginFetch } from '@kubb\u002Fplugin-fetch'\n\npluginFetch({ throwOnErrorDefault: false })\n\n\u002F\u002F resolves with an error result\nconst list = await searchPets({ query: { status: 'available' } })\n\n\u002F\u002F opt one call back into throwing\nconst pet = await getPetById({ path: { petId: 1 }, throwOnError: true })",[15,636,637,65,653,65,655,65,670,65,672,65,677,65,709,65,711,65,716],{"class":37},[39,638,639,641,643,646,648,650],{"class":41,"style":42},[39,640,46],{"style":45},[39,642,50],{"style":49},[39,644,645],{"style":53},"pluginFetch ",[39,647,57],{"style":49},[39,649,60],{"style":45},[39,651,652],{"style":63},"'@kubb\u002Fplugin-fetch'",[39,654],{"class":41,"style":42},[39,656,657,660,662,664,666,668],{"class":41,"style":42},[39,658,659],{"style":74},"pluginFetch",[39,661,119],{"style":49},[39,663,627],{"style":49},[39,665,125],{"style":45},[39,667,511],{"style":49},[39,669,514],{"style":49},[39,671],{"class":41,"style":42},[39,673,674],{"class":41,"style":42},[39,675,676],{"style":229},"\u002F\u002F resolves with an error result",[39,678,679,681,684,686,688,691,693,696,698,700,702,704,707],{"class":41,"style":42},[39,680,100],{"style":45},[39,682,683],{"style":53},"list ",[39,685,110],{"style":45},[39,687,113],{"style":45},[39,689,690],{"style":74},"searchPets",[39,692,119],{"style":49},[39,694,695],{"style":49},"query",[39,697,125],{"style":45},[39,699,50],{"style":49},[39,701,223],{"style":49},[39,703,125],{"style":45},[39,705,706],{"style":63},"'available' ",[39,708,138],{"style":49},[39,710],{"class":41,"style":42},[39,712,713],{"class":41,"style":42},[39,714,715],{"style":229},"\u002F\u002F opt one call back into throwing",[39,717,718,720,723,725,727,729,731,733,735,737,739,741,743,745,747,749,751,754],{"class":41,"style":42},[39,719,100],{"style":45},[39,721,722],{"style":53},"pet ",[39,724,110],{"style":45},[39,726,113],{"style":45},[39,728,116],{"style":74},[39,730,119],{"style":49},[39,732,122],{"style":49},[39,734,125],{"style":45},[39,736,50],{"style":49},[39,738,130],{"style":49},[39,740,125],{"style":45},[39,742,135],{"style":49},[39,744,260],{"style":49},[39,746,335],{"style":45},[39,748,21],{"style":49},[39,750,125],{"style":45},[39,752,753],{"style":49},"true ",[39,755,514],{"style":49},[11,757,758,761],{},[15,759,760],{},"client.setConfig({ throwOnError })"," does not change this default, because each generated\noperation passes its own value. Set it on the plugin.",[446,763,765],{"id":764},"network-failures-still-throw","Network failures still throw",[767,768,770,771,773,774,777,778,780,781,784],"blockquote",{"as":769},"important","",[15,772,21],{}," only applies when the server answers. A dropped connection, a DNS failure, or an\naborted ",[15,775,776],{},"AbortSignal"," always rejects. A ",[15,779,17],{}," means the server answered with a non-2xx\nstatus, and a ",[15,782,783],{},"ParseError"," means a body failed validation. Any other error usually means the\nrequest never completed.",[30,786,788],{"language":32,"code":787,"class":34},"try {\n  const { data } = await getPetById({ path: { petId: 1 }, throwOnError: false })\n  use(data)\n} catch (error) {\n  \u002F\u002F not a ResponseError: the request never completed\n  console.error('request failed to send', error)\n}",[15,789,790,65,796,65,840,65,853,65,865,65,872,65,893],{"class":37},[39,791,792,794],{"class":41,"style":42},[39,793,89],{"style":45},[39,795,92],{"style":49},[39,797,798,800,802,804,806,808,810,812,814,816,818,820,822,824,826,828,830,832,834,836,838],{"class":41,"style":42},[39,799,97],{"style":49},[39,801,100],{"style":45},[39,803,50],{"style":49},[39,805,105],{"style":53},[39,807,57],{"style":49},[39,809,110],{"style":45},[39,811,113],{"style":45},[39,813,116],{"style":74},[39,815,119],{"style":49},[39,817,122],{"style":49},[39,819,125],{"style":45},[39,821,50],{"style":49},[39,823,130],{"style":49},[39,825,125],{"style":45},[39,827,135],{"style":49},[39,829,260],{"style":49},[39,831,335],{"style":45},[39,833,21],{"style":49},[39,835,125],{"style":45},[39,837,511],{"style":49},[39,839,514],{"style":49},[39,841,842,844,847,849,851],{"class":41,"style":42},[39,843,97],{"style":49},[39,845,846],{"style":74},"use",[39,848,154],{"style":49},[39,850,157],{"style":53},[39,852,165],{"style":49},[39,854,855,857,859,861,863],{"class":41,"style":42},[39,856,57],{"style":49},[39,858,172],{"style":45},[39,860,154],{"style":49},[39,862,177],{"style":53},[39,864,180],{"style":49},[39,866,867,869],{"class":41,"style":42},[39,868,97],{"style":49},[39,870,871],{"style":229},"\u002F\u002F not a ResponseError: the request never completed",[39,873,874,876,878,880,882,884,887,889,891],{"class":41,"style":42},[39,875,97],{"style":229},[39,877,145],{"style":53},[39,879,148],{"style":45},[39,881,177],{"style":74},[39,883,154],{"style":49},[39,885,886],{"style":63},"'request failed to send'",[39,888,335],{"style":45},[39,890,177],{"style":53},[39,892,165],{"style":49},[39,894,895],{"class":41,"style":42},[39,896,260],{"style":49},[11,898,899,900,902],{},"Pass an ",[15,901,776],{}," to cancel a request. The call rejects with the abort reason.",[446,904,906],{"id":905},"validation-failures","Validation failures",[11,908,909,910,913,914,916,917,631],{},"When you turn on the ",[15,911,912],{},"validator"," option, a body that does not match its Zod schema throws a\n",[15,915,783],{}," instead of returning. It carries the schema's raw ",[15,918,919],{},"issues",[30,921,923],{"language":32,"code":922,"class":34},"import { ParseError } from '.\u002Fgen\u002F.kubb\u002FstandardSchema'\n\ntry {\n  const { data } = await getPetById({ path: { petId: 1 } })\n  use(data)\n} catch (error) {\n  if (error instanceof ParseError) {\n    console.error(error.issues) \u002F\u002F [{ message, path }]\n  }\n}",[15,924,925,65,941,65,943,65,949,65,983,65,995,65,1007,65,1024,65,1047,65,1053],{"class":37},[39,926,927,929,931,934,936,938],{"class":41,"style":42},[39,928,46],{"style":45},[39,930,50],{"style":49},[39,932,933],{"style":74},"ParseError ",[39,935,57],{"style":49},[39,937,60],{"style":45},[39,939,940],{"style":63},"'.\u002Fgen\u002F.kubb\u002FstandardSchema'",[39,942],{"class":41,"style":42},[39,944,945,947],{"class":41,"style":42},[39,946,89],{"style":45},[39,948,92],{"style":49},[39,950,951,953,955,957,959,961,963,965,967,969,971,973,975,977,979,981],{"class":41,"style":42},[39,952,97],{"style":49},[39,954,100],{"style":45},[39,956,50],{"style":49},[39,958,105],{"style":53},[39,960,57],{"style":49},[39,962,110],{"style":45},[39,964,113],{"style":45},[39,966,116],{"style":74},[39,968,119],{"style":49},[39,970,122],{"style":49},[39,972,125],{"style":45},[39,974,50],{"style":49},[39,976,130],{"style":49},[39,978,125],{"style":45},[39,980,135],{"style":49},[39,982,138],{"style":49},[39,984,985,987,989,991,993],{"class":41,"style":42},[39,986,97],{"style":49},[39,988,846],{"style":74},[39,990,154],{"style":49},[39,992,157],{"style":53},[39,994,165],{"style":49},[39,996,997,999,1001,1003,1005],{"class":41,"style":42},[39,998,57],{"style":49},[39,1000,172],{"style":45},[39,1002,154],{"style":49},[39,1004,177],{"style":53},[39,1006,180],{"style":49},[39,1008,1009,1011,1013,1015,1017,1020,1022],{"class":41,"style":42},[39,1010,97],{"style":49},[39,1012,187],{"style":45},[39,1014,154],{"style":49},[39,1016,322],{"style":53},[39,1018,1019],{"style":45},"instanceof ",[39,1021,783],{"style":74},[39,1023,180],{"style":49},[39,1025,1026,1028,1030,1032,1034,1036,1038,1040,1042,1044],{"class":41,"style":42},[39,1027,208],{"style":49},[39,1029,145],{"style":53},[39,1031,148],{"style":45},[39,1033,177],{"style":74},[39,1035,154],{"style":49},[39,1037,177],{"style":53},[39,1039,148],{"style":45},[39,1041,919],{"style":49},[39,1043,226],{"style":49},[39,1045,1046],{"style":229},"\u002F\u002F [{ message, path }]",[39,1048,1049,1051],{"class":41,"style":42},[39,1050,97],{"style":229},[39,1052,260],{"style":49},[39,1054,1055],{"class":41,"style":42},[39,1056,260],{"style":49},[11,1058,1059,1060,1062,1063,1065,1066,1068],{},"A ",[15,1061,783],{}," reports schema validation issues. A ",[15,1064,17],{}," reports a non-2xx status. With ",[15,1067,455],{},", the error body is checked against its own error schema.",[11,1070,1071,1072,1075,1076,1078,1079,1081,1082,1085,1086,1089],{},"Calling ",[15,1073,1074],{},".unwrap()"," on a ",[15,1077,455],{}," call turns that same ",[15,1080,177],{}," into a rejection, so a\n",[15,1083,1084],{},"try","\u002F",[15,1087,1088],{},"catch"," works there too.",{"title":770,"searchDepth":1091,"depth":1091,"links":1092},5,[1093,1095,1096,1097],{"id":448,"depth":1094,"text":449},2,{"id":620,"depth":1094,"text":621},{"id":764,"depth":1094,"text":765},{"id":905,"depth":1094,"text":906},"\u002Fextensions\u002Fkubb-labs\u002Fplugin-fetch\u002Fguides\u002Ferror-handling",1793747914767]