[{"data":1,"prerenderedAt":3547},["ShallowReactive",2],{"page-\u002Fdart\u002F11-error-handling":3},{"id":4,"title":5,"body":6,"description":3540,"extension":3541,"meta":3542,"navigation":64,"path":3543,"seo":3544,"stem":3545,"__hash__":3546},"content\u002Fdart\u002F11-error-handling.md","Dart — Exceptions, Error Hierarchy & Async Error Propagation",{"type":7,"value":8,"toc":3525},"minimark",[9,13,26,360,364,1050,1060,1352,1356,1604,1608,1936,1940,2362,2369,2729,2733,2834,2838,3018,3022,3026,3165,3168,3521],[10,11,5],"h1",{"id":12},"dart-exceptions-error-hierarchy-async-error-propagation",[14,15,17,21,22,25],"h2",{"id":16},"exception-vs-error-semantic-boundary",[18,19,20],"code",{},"Exception"," vs ",[18,23,24],{},"Error"," — Semantic Boundary",[27,28,30],"code-wrapper",{"language":29},"dart",[31,32,36],"pre",{"className":33,"code":34,"language":29,"meta":35,"style":35},"language-dart shiki shiki-themes github-light github-dark","\u002F\u002F ── Exception: recoverable runtime conditions a program SHOULD catch. ──\n\u002F\u002F   - Network failures, bad input, missing files, API errors.\n\u002F\u002F   - The program can recover (retry, fallback, show error to user).\n\n\u002F\u002F ── Error: programming bugs that should CRASH (not be caught). ──\n\u002F\u002F   - StateError, RangeError, NoSuchMethodError, AssertionError.\n\u002F\u002F   - The program has a bug — catching it hides the bug. Fix the code.\n\n\u002F\u002F ❌ Anti-pattern: catching Errors (hides bugs).\nvoid bad(List\u003Cint> list) {\n  try {\n    list[10].abs();  \u002F\u002F RangeError — a bug in the code\n  } catch (e) {\n    \u002F\u002F Swallowed — the bug is invisible. The list was too short.\n    \u002F\u002F The program continues in a broken state.\n  }\n}\n\n\u002F\u002F ✓ Correct: catch Exceptions (recoverable), let Errors crash.\nvoid good(List\u003Cint> list) {\n  try {\n    final data = fetchData();  \u002F\u002F may throw HttpException (recoverable)\n    processData(data);\n  } on HttpException catch (e) {\n    \u002F\u002F Recover: retry, cache, show user.\n    showRetryDialog(e);\n  }\n  \u002F\u002F RangeError from list[10] propagates — crashes, visible in stack trace.\n}\n\n\u002F\u002F The Error hierarchy:\n\u002F\u002F ArgumentError       — invalid argument value\n\u002F\u002F StateError          — object in a bad state (e.g., calling close() twice)\n\u002F\u002F RangeError          — value\u002Findex out of range\n\u002F\u002F NoSuchMethodError   — method doesn't exist (usually from `dynamic`)\n\u002F\u002F UnsupportedError     — operation not supported (e.g., modify unmodifiable list)\n\u002F\u002F ConcurrentModificationError — collection modified during iteration\n\u002F\u002F LateInitializationError — `late` var read before assignment\n\u002F\u002F AssertionError      — `assert` failed (debug only)\n","",[18,37,38,47,53,59,66,72,78,84,89,95,123,132,153,165,171,177,183,189,194,200,218,225,245,254,270,276,285,290,296,301,306,312,318,324,330,336,342,348,354],{"__ignoreMap":35},[39,40,43],"span",{"class":41,"line":42},"line",1,[39,44,46],{"class":45},"sdCPZ","\u002F\u002F ── Exception: recoverable runtime conditions a program SHOULD catch. ──\n",[39,48,50],{"class":41,"line":49},2,[39,51,52],{"class":45},"\u002F\u002F   - Network failures, bad input, missing files, API errors.\n",[39,54,56],{"class":41,"line":55},3,[39,57,58],{"class":45},"\u002F\u002F   - The program can recover (retry, fallback, show error to user).\n",[39,60,62],{"class":41,"line":61},4,[39,63,65],{"emptyLinePlaceholder":64},true,"\n",[39,67,69],{"class":41,"line":68},5,[39,70,71],{"class":45},"\u002F\u002F ── Error: programming bugs that should CRASH (not be caught). ──\n",[39,73,75],{"class":41,"line":74},6,[39,76,77],{"class":45},"\u002F\u002F   - StateError, RangeError, NoSuchMethodError, AssertionError.\n",[39,79,81],{"class":41,"line":80},7,[39,82,83],{"class":45},"\u002F\u002F   - The program has a bug — catching it hides the bug. Fix the code.\n",[39,85,87],{"class":41,"line":86},8,[39,88,65],{"emptyLinePlaceholder":64},[39,90,92],{"class":41,"line":91},9,[39,93,94],{"class":45},"\u002F\u002F ❌ Anti-pattern: catching Errors (hides bugs).\n",[39,96,98,102,106,110,114,117,120],{"class":41,"line":97},10,[39,99,101],{"class":100},"svdQ7","void",[39,103,105],{"class":104},"sIsaT"," bad",[39,107,109],{"class":108},"ssxIu","(",[39,111,113],{"class":112},"snvgF","List",[39,115,116],{"class":108},"\u003C",[39,118,119],{"class":112},"int",[39,121,122],{"class":108},"> list) {\n",[39,124,126,129],{"class":41,"line":125},11,[39,127,128],{"class":100},"  try",[39,130,131],{"class":108}," {\n",[39,133,135,138,141,144,147,150],{"class":41,"line":134},12,[39,136,137],{"class":108},"    list[",[39,139,140],{"class":112},"10",[39,142,143],{"class":108},"].",[39,145,146],{"class":104},"abs",[39,148,149],{"class":108},"();  ",[39,151,152],{"class":45},"\u002F\u002F RangeError — a bug in the code\n",[39,154,156,159,162],{"class":41,"line":155},13,[39,157,158],{"class":108},"  } ",[39,160,161],{"class":100},"catch",[39,163,164],{"class":108}," (e) {\n",[39,166,168],{"class":41,"line":167},14,[39,169,170],{"class":45},"    \u002F\u002F Swallowed — the bug is invisible. The list was too short.\n",[39,172,174],{"class":41,"line":173},15,[39,175,176],{"class":45},"    \u002F\u002F The program continues in a broken state.\n",[39,178,180],{"class":41,"line":179},16,[39,181,182],{"class":108},"  }\n",[39,184,186],{"class":41,"line":185},17,[39,187,188],{"class":108},"}\n",[39,190,192],{"class":41,"line":191},18,[39,193,65],{"emptyLinePlaceholder":64},[39,195,197],{"class":41,"line":196},19,[39,198,199],{"class":45},"\u002F\u002F ✓ Correct: catch Exceptions (recoverable), let Errors crash.\n",[39,201,203,205,208,210,212,214,216],{"class":41,"line":202},20,[39,204,101],{"class":100},[39,206,207],{"class":104}," good",[39,209,109],{"class":108},[39,211,113],{"class":112},[39,213,116],{"class":108},[39,215,119],{"class":112},[39,217,122],{"class":108},[39,219,221,223],{"class":41,"line":220},21,[39,222,128],{"class":100},[39,224,131],{"class":108},[39,226,228,231,234,237,240,242],{"class":41,"line":227},22,[39,229,230],{"class":100},"    final",[39,232,233],{"class":108}," data ",[39,235,236],{"class":100},"=",[39,238,239],{"class":104}," fetchData",[39,241,149],{"class":108},[39,243,244],{"class":45},"\u002F\u002F may throw HttpException (recoverable)\n",[39,246,248,251],{"class":41,"line":247},23,[39,249,250],{"class":104},"    processData",[39,252,253],{"class":108},"(data);\n",[39,255,257,259,262,265,268],{"class":41,"line":256},24,[39,258,158],{"class":108},[39,260,261],{"class":100},"on",[39,263,264],{"class":112}," HttpException",[39,266,267],{"class":100}," catch",[39,269,164],{"class":108},[39,271,273],{"class":41,"line":272},25,[39,274,275],{"class":45},"    \u002F\u002F Recover: retry, cache, show user.\n",[39,277,279,282],{"class":41,"line":278},26,[39,280,281],{"class":104},"    showRetryDialog",[39,283,284],{"class":108},"(e);\n",[39,286,288],{"class":41,"line":287},27,[39,289,182],{"class":108},[39,291,293],{"class":41,"line":292},28,[39,294,295],{"class":45},"  \u002F\u002F RangeError from list[10] propagates — crashes, visible in stack trace.\n",[39,297,299],{"class":41,"line":298},29,[39,300,188],{"class":108},[39,302,304],{"class":41,"line":303},30,[39,305,65],{"emptyLinePlaceholder":64},[39,307,309],{"class":41,"line":308},31,[39,310,311],{"class":45},"\u002F\u002F The Error hierarchy:\n",[39,313,315],{"class":41,"line":314},32,[39,316,317],{"class":45},"\u002F\u002F ArgumentError       — invalid argument value\n",[39,319,321],{"class":41,"line":320},33,[39,322,323],{"class":45},"\u002F\u002F StateError          — object in a bad state (e.g., calling close() twice)\n",[39,325,327],{"class":41,"line":326},34,[39,328,329],{"class":45},"\u002F\u002F RangeError          — value\u002Findex out of range\n",[39,331,333],{"class":41,"line":332},35,[39,334,335],{"class":45},"\u002F\u002F NoSuchMethodError   — method doesn't exist (usually from `dynamic`)\n",[39,337,339],{"class":41,"line":338},36,[39,340,341],{"class":45},"\u002F\u002F UnsupportedError     — operation not supported (e.g., modify unmodifiable list)\n",[39,343,345],{"class":41,"line":344},37,[39,346,347],{"class":45},"\u002F\u002F ConcurrentModificationError — collection modified during iteration\n",[39,349,351],{"class":41,"line":350},38,[39,352,353],{"class":45},"\u002F\u002F LateInitializationError — `late` var read before assignment\n",[39,355,357],{"class":41,"line":356},39,[39,358,359],{"class":45},"\u002F\u002F AssertionError      — `assert` failed (debug only)\n",[14,361,363],{"id":362},"custom-exceptions-production-design","Custom Exceptions — Production Design",[27,365,366],{"language":29},[31,367,369],{"className":33,"code":368,"language":29,"meta":35,"style":35},"\u002F\u002F Design custom exceptions with: a message, structured fields, toString().\n\u002F\u002F Implement Exception (marker interface) — enables `on Exception` to catch it.\n\nclass ApiException implements Exception {\n  final String message;\n  final int? statusCode;\n  final String? endpoint;\n  final Map\u003CString, dynamic>? details;\n\n  const ApiException(\n    this.message, {\n    this.statusCode,\n    this.endpoint,\n    this.details,\n  });\n\n  @override\n  String toString() {\n    final parts = \u003CString>['ApiException: $message'];\n    if (statusCode != null) parts.add('status=$statusCode');\n    if (endpoint != null) parts.add('endpoint=$endpoint');\n    return parts.join(' | ');\n  }\n}\n\n\u002F\u002F Domain-specific exceptions with a sealed hierarchy:\nsealed class AppException implements Exception {\n  final String message;\n  const AppException(this.message);\n}\n\nclass NetworkException extends AppException {\n  final int? statusCode;\n  const NetworkException(super.message, {this.statusCode});\n}\n\nclass ValidationException extends AppException {\n  final String field;\n  const ValidationException(super.message, {required this.field});\n}\n\nclass AuthException extends AppException {\n  const AuthException(super.message);\n}\n\n\u002F\u002F Usage — catch specific types for specific recovery:\nFuture\u003Cvoid> handleRequest() async {\n  try {\n    await process();\n  } on NetworkException catch (e) {\n    if (e.statusCode == 429) return retryAfterDelay();\n    throw e;  \u002F\u002F rethrow other network errors\n  } on ValidationException catch (e) {\n    return BadRequest(error: '${e.field}: ${e.message}');\n  } on AuthException {\n    return Unauthorized();\n  }\n  \u002F\u002F Unknown exceptions propagate (don't catch broadly).\n}\n",[18,370,371,376,381,385,401,412,425,436,462,466,476,484,491,498,505,510,514,519,530,565,600,629,647,651,655,659,664,681,689,703,707,711,725,735,754,758,762,775,784,805,810,815,829,842,847,852,858,882,889,901,914,939,951,964,1013,1024,1034,1039,1045],{"__ignoreMap":35},[39,372,373],{"class":41,"line":42},[39,374,375],{"class":45},"\u002F\u002F Design custom exceptions with: a message, structured fields, toString().\n",[39,377,378],{"class":41,"line":49},[39,379,380],{"class":45},"\u002F\u002F Implement Exception (marker interface) — enables `on Exception` to catch it.\n",[39,382,383],{"class":41,"line":55},[39,384,65],{"emptyLinePlaceholder":64},[39,386,387,390,393,396,399],{"class":41,"line":61},[39,388,389],{"class":100},"class",[39,391,392],{"class":112}," ApiException",[39,394,395],{"class":100}," implements",[39,397,398],{"class":112}," Exception",[39,400,131],{"class":108},[39,402,403,406,409],{"class":41,"line":68},[39,404,405],{"class":100},"  final",[39,407,408],{"class":112}," String",[39,410,411],{"class":108}," message;\n",[39,413,414,416,419,422],{"class":41,"line":74},[39,415,405],{"class":100},[39,417,418],{"class":112}," int",[39,420,421],{"class":100},"?",[39,423,424],{"class":108}," statusCode;\n",[39,426,427,429,431,433],{"class":41,"line":80},[39,428,405],{"class":100},[39,430,408],{"class":112},[39,432,421],{"class":100},[39,434,435],{"class":108}," endpoint;\n",[39,437,438,440,443,445,448,451,454,457,459],{"class":41,"line":86},[39,439,405],{"class":100},[39,441,442],{"class":112}," Map",[39,444,116],{"class":108},[39,446,447],{"class":112},"String",[39,449,450],{"class":108},", ",[39,452,453],{"class":112},"dynamic",[39,455,456],{"class":108},">",[39,458,421],{"class":100},[39,460,461],{"class":108}," details;\n",[39,463,464],{"class":41,"line":91},[39,465,65],{"emptyLinePlaceholder":64},[39,467,468,471,473],{"class":41,"line":97},[39,469,470],{"class":100},"  const",[39,472,392],{"class":112},[39,474,475],{"class":108},"(\n",[39,477,478,481],{"class":41,"line":125},[39,479,480],{"class":112},"    this",[39,482,483],{"class":108},".message, {\n",[39,485,486,488],{"class":41,"line":134},[39,487,480],{"class":112},[39,489,490],{"class":108},".statusCode,\n",[39,492,493,495],{"class":41,"line":155},[39,494,480],{"class":112},[39,496,497],{"class":108},".endpoint,\n",[39,499,500,502],{"class":41,"line":167},[39,501,480],{"class":112},[39,503,504],{"class":108},".details,\n",[39,506,507],{"class":41,"line":173},[39,508,509],{"class":108},"  });\n",[39,511,512],{"class":41,"line":179},[39,513,65],{"emptyLinePlaceholder":64},[39,515,516],{"class":41,"line":185},[39,517,518],{"class":100},"  @override\n",[39,520,521,524,527],{"class":41,"line":191},[39,522,523],{"class":112},"  String",[39,525,526],{"class":104}," toString",[39,528,529],{"class":108},"() {\n",[39,531,532,534,537,539,542,544,546,549,553,556,559,562],{"class":41,"line":196},[39,533,230],{"class":100},[39,535,536],{"class":108}," parts ",[39,538,236],{"class":100},[39,540,541],{"class":100}," \u003C",[39,543,447],{"class":112},[39,545,456],{"class":100},[39,547,548],{"class":108},"[",[39,550,552],{"class":551},"sJ6F3","'ApiException: ",[39,554,555],{"class":551},"$",[39,557,558],{"class":112},"message",[39,560,561],{"class":551},"'",[39,563,564],{"class":108},"];\n",[39,566,567,570,573,576,579,582,585,587,590,592,595,597],{"class":41,"line":202},[39,568,569],{"class":100},"    if",[39,571,572],{"class":108}," (statusCode ",[39,574,575],{"class":100},"!=",[39,577,578],{"class":112}," null",[39,580,581],{"class":108},") parts.",[39,583,584],{"class":104},"add",[39,586,109],{"class":108},[39,588,589],{"class":551},"'status=",[39,591,555],{"class":551},[39,593,594],{"class":112},"statusCode",[39,596,561],{"class":551},[39,598,599],{"class":108},");\n",[39,601,602,604,607,609,611,613,615,617,620,622,625,627],{"class":41,"line":220},[39,603,569],{"class":100},[39,605,606],{"class":108}," (endpoint ",[39,608,575],{"class":100},[39,610,578],{"class":112},[39,612,581],{"class":108},[39,614,584],{"class":104},[39,616,109],{"class":108},[39,618,619],{"class":551},"'endpoint=",[39,621,555],{"class":551},[39,623,624],{"class":112},"endpoint",[39,626,561],{"class":551},[39,628,599],{"class":108},[39,630,631,634,637,640,642,645],{"class":41,"line":227},[39,632,633],{"class":100},"    return",[39,635,636],{"class":108}," parts.",[39,638,639],{"class":104},"join",[39,641,109],{"class":108},[39,643,644],{"class":551},"' | '",[39,646,599],{"class":108},[39,648,649],{"class":41,"line":247},[39,650,182],{"class":108},[39,652,653],{"class":41,"line":256},[39,654,188],{"class":108},[39,656,657],{"class":41,"line":272},[39,658,65],{"emptyLinePlaceholder":64},[39,660,661],{"class":41,"line":278},[39,662,663],{"class":45},"\u002F\u002F Domain-specific exceptions with a sealed hierarchy:\n",[39,665,666,669,672,675,677,679],{"class":41,"line":287},[39,667,668],{"class":100},"sealed",[39,670,671],{"class":100}," class",[39,673,674],{"class":112}," AppException",[39,676,395],{"class":100},[39,678,398],{"class":112},[39,680,131],{"class":108},[39,682,683,685,687],{"class":41,"line":292},[39,684,405],{"class":100},[39,686,408],{"class":112},[39,688,411],{"class":108},[39,690,691,693,695,697,700],{"class":41,"line":298},[39,692,470],{"class":100},[39,694,674],{"class":112},[39,696,109],{"class":108},[39,698,699],{"class":112},"this",[39,701,702],{"class":108},".message);\n",[39,704,705],{"class":41,"line":303},[39,706,188],{"class":108},[39,708,709],{"class":41,"line":308},[39,710,65],{"emptyLinePlaceholder":64},[39,712,713,715,718,721,723],{"class":41,"line":314},[39,714,389],{"class":100},[39,716,717],{"class":112}," NetworkException",[39,719,720],{"class":100}," extends",[39,722,674],{"class":112},[39,724,131],{"class":108},[39,726,727,729,731,733],{"class":41,"line":320},[39,728,405],{"class":100},[39,730,418],{"class":112},[39,732,421],{"class":100},[39,734,424],{"class":108},[39,736,737,739,741,743,746,749,751],{"class":41,"line":326},[39,738,470],{"class":100},[39,740,717],{"class":112},[39,742,109],{"class":108},[39,744,745],{"class":112},"super",[39,747,748],{"class":108},".message, {",[39,750,699],{"class":112},[39,752,753],{"class":108},".statusCode});\n",[39,755,756],{"class":41,"line":332},[39,757,188],{"class":108},[39,759,760],{"class":41,"line":338},[39,761,65],{"emptyLinePlaceholder":64},[39,763,764,766,769,771,773],{"class":41,"line":344},[39,765,389],{"class":100},[39,767,768],{"class":112}," ValidationException",[39,770,720],{"class":100},[39,772,674],{"class":112},[39,774,131],{"class":108},[39,776,777,779,781],{"class":41,"line":350},[39,778,405],{"class":100},[39,780,408],{"class":112},[39,782,783],{"class":108}," field;\n",[39,785,786,788,790,792,794,796,799,802],{"class":41,"line":356},[39,787,470],{"class":100},[39,789,768],{"class":112},[39,791,109],{"class":108},[39,793,745],{"class":112},[39,795,748],{"class":108},[39,797,798],{"class":100},"required",[39,800,801],{"class":112}," this",[39,803,804],{"class":108},".field});\n",[39,806,808],{"class":41,"line":807},40,[39,809,188],{"class":108},[39,811,813],{"class":41,"line":812},41,[39,814,65],{"emptyLinePlaceholder":64},[39,816,818,820,823,825,827],{"class":41,"line":817},42,[39,819,389],{"class":100},[39,821,822],{"class":112}," AuthException",[39,824,720],{"class":100},[39,826,674],{"class":112},[39,828,131],{"class":108},[39,830,832,834,836,838,840],{"class":41,"line":831},43,[39,833,470],{"class":100},[39,835,822],{"class":112},[39,837,109],{"class":108},[39,839,745],{"class":112},[39,841,702],{"class":108},[39,843,845],{"class":41,"line":844},44,[39,846,188],{"class":108},[39,848,850],{"class":41,"line":849},45,[39,851,65],{"emptyLinePlaceholder":64},[39,853,855],{"class":41,"line":854},46,[39,856,857],{"class":45},"\u002F\u002F Usage — catch specific types for specific recovery:\n",[39,859,861,864,866,868,871,874,877,880],{"class":41,"line":860},47,[39,862,863],{"class":112},"Future",[39,865,116],{"class":108},[39,867,101],{"class":100},[39,869,870],{"class":108},"> ",[39,872,873],{"class":104},"handleRequest",[39,875,876],{"class":108},"() ",[39,878,879],{"class":100},"async",[39,881,131],{"class":108},[39,883,885,887],{"class":41,"line":884},48,[39,886,128],{"class":100},[39,888,131],{"class":108},[39,890,892,895,898],{"class":41,"line":891},49,[39,893,894],{"class":100},"    await",[39,896,897],{"class":104}," process",[39,899,900],{"class":108},"();\n",[39,902,904,906,908,910,912],{"class":41,"line":903},50,[39,905,158],{"class":108},[39,907,261],{"class":100},[39,909,717],{"class":112},[39,911,267],{"class":100},[39,913,164],{"class":108},[39,915,917,919,922,925,928,931,934,937],{"class":41,"line":916},51,[39,918,569],{"class":100},[39,920,921],{"class":108}," (e.statusCode ",[39,923,924],{"class":100},"==",[39,926,927],{"class":112}," 429",[39,929,930],{"class":108},") ",[39,932,933],{"class":100},"return",[39,935,936],{"class":104}," retryAfterDelay",[39,938,900],{"class":108},[39,940,942,945,948],{"class":41,"line":941},52,[39,943,944],{"class":100},"    throw",[39,946,947],{"class":108}," e;  ",[39,949,950],{"class":45},"\u002F\u002F rethrow other network errors\n",[39,952,954,956,958,960,962],{"class":41,"line":953},53,[39,955,158],{"class":108},[39,957,261],{"class":100},[39,959,768],{"class":112},[39,961,267],{"class":100},[39,963,164],{"class":108},[39,965,967,969,972,975,978,981,984,987,990,993,996,999,1001,1003,1005,1007,1009,1011],{"class":41,"line":966},54,[39,968,633],{"class":100},[39,970,971],{"class":112}," BadRequest",[39,973,974],{"class":108},"(error",[39,976,977],{"class":100},":",[39,979,980],{"class":551}," '",[39,982,983],{"class":551},"${",[39,985,986],{"class":112},"e",[39,988,989],{"class":551},".",[39,991,992],{"class":112},"field",[39,994,995],{"class":551},"}",[39,997,998],{"class":551},": ",[39,1000,983],{"class":551},[39,1002,986],{"class":112},[39,1004,989],{"class":551},[39,1006,558],{"class":112},[39,1008,995],{"class":551},[39,1010,561],{"class":551},[39,1012,599],{"class":108},[39,1014,1016,1018,1020,1022],{"class":41,"line":1015},55,[39,1017,158],{"class":108},[39,1019,261],{"class":100},[39,1021,822],{"class":112},[39,1023,131],{"class":108},[39,1025,1027,1029,1032],{"class":41,"line":1026},56,[39,1028,633],{"class":100},[39,1030,1031],{"class":112}," Unauthorized",[39,1033,900],{"class":108},[39,1035,1037],{"class":41,"line":1036},57,[39,1038,182],{"class":108},[39,1040,1042],{"class":41,"line":1041},58,[39,1043,1044],{"class":45},"  \u002F\u002F Unknown exceptions propagate (don't catch broadly).\n",[39,1046,1048],{"class":41,"line":1047},59,[39,1049,188],{"class":108},[14,1051,1053,21,1056,1059],{"id":1052},"rethrow-vs-throw-e-stack-trace-preservation",[18,1054,1055],{},"rethrow",[18,1057,1058],{},"throw e"," — Stack Trace Preservation",[27,1061,1062],{"language":29},[31,1063,1065],{"className":33,"code":1064,"language":29,"meta":35,"style":35},"\u002F\u002F ── rethrow: preserves the ORIGINAL stack trace. ──\n\u002F\u002F The error appears to originate from where it was first thrown.\n\u002F\u002F Use when you log\u002Fhandle partially but want the caller to also handle.\n\n\u002F\u002F ── throw e: resets the stack trace to THIS line. ──\n\u002F\u002F The original location is lost — debugging is harder.\n\n\u002F\u002F ❌ Anti-pattern: throw e (loses the original stack trace).\nFuture\u003Cvoid> badHandler() async {\n  try {\n    await riskyOperation();\n  } catch (e) {\n    log(e);\n    throw e;  \u002F\u002F ← stack trace now starts here, not in riskyOperation\n  }\n}\n\n\u002F\u002F ✓ Correct: rethrow (preserves the original stack trace).\nFuture\u003Cvoid> goodHandler() async {\n  try {\n    await riskyOperation();\n  } catch (e, stackTrace) {\n    log(e, stackTrace);\n    rethrow;  \u002F\u002F ← preserves the original throw location\n  }\n}\n\n\u002F\u002F Capturing the stack trace explicitly:\nFuture\u003Cvoid> withStackTrace() async {\n  try {\n    await riskyOperation();\n  } on SpecificException catch (e, stackTrace) {\n    \u002F\u002F `stackTrace` is the original stack — log it for debugging.\n    logger.error(e, stackTrace);\n    rethrow;\n  } catch (e) {\n    \u002F\u002F No stack trace variable — use rethrow to preserve it.\n    rethrow;\n  }\n}\n",[18,1066,1067,1072,1077,1082,1086,1091,1096,1100,1105,1124,1130,1139,1147,1154,1163,1167,1171,1175,1180,1199,1205,1213,1222,1229,1240,1244,1248,1252,1257,1276,1282,1290,1303,1308,1318,1325,1333,1338,1344,1348],{"__ignoreMap":35},[39,1068,1069],{"class":41,"line":42},[39,1070,1071],{"class":45},"\u002F\u002F ── rethrow: preserves the ORIGINAL stack trace. ──\n",[39,1073,1074],{"class":41,"line":49},[39,1075,1076],{"class":45},"\u002F\u002F The error appears to originate from where it was first thrown.\n",[39,1078,1079],{"class":41,"line":55},[39,1080,1081],{"class":45},"\u002F\u002F Use when you log\u002Fhandle partially but want the caller to also handle.\n",[39,1083,1084],{"class":41,"line":61},[39,1085,65],{"emptyLinePlaceholder":64},[39,1087,1088],{"class":41,"line":68},[39,1089,1090],{"class":45},"\u002F\u002F ── throw e: resets the stack trace to THIS line. ──\n",[39,1092,1093],{"class":41,"line":74},[39,1094,1095],{"class":45},"\u002F\u002F The original location is lost — debugging is harder.\n",[39,1097,1098],{"class":41,"line":80},[39,1099,65],{"emptyLinePlaceholder":64},[39,1101,1102],{"class":41,"line":86},[39,1103,1104],{"class":45},"\u002F\u002F ❌ Anti-pattern: throw e (loses the original stack trace).\n",[39,1106,1107,1109,1111,1113,1115,1118,1120,1122],{"class":41,"line":91},[39,1108,863],{"class":112},[39,1110,116],{"class":108},[39,1112,101],{"class":100},[39,1114,870],{"class":108},[39,1116,1117],{"class":104},"badHandler",[39,1119,876],{"class":108},[39,1121,879],{"class":100},[39,1123,131],{"class":108},[39,1125,1126,1128],{"class":41,"line":97},[39,1127,128],{"class":100},[39,1129,131],{"class":108},[39,1131,1132,1134,1137],{"class":41,"line":125},[39,1133,894],{"class":100},[39,1135,1136],{"class":104}," riskyOperation",[39,1138,900],{"class":108},[39,1140,1141,1143,1145],{"class":41,"line":134},[39,1142,158],{"class":108},[39,1144,161],{"class":100},[39,1146,164],{"class":108},[39,1148,1149,1152],{"class":41,"line":155},[39,1150,1151],{"class":104},"    log",[39,1153,284],{"class":108},[39,1155,1156,1158,1160],{"class":41,"line":167},[39,1157,944],{"class":100},[39,1159,947],{"class":108},[39,1161,1162],{"class":45},"\u002F\u002F ← stack trace now starts here, not in riskyOperation\n",[39,1164,1165],{"class":41,"line":173},[39,1166,182],{"class":108},[39,1168,1169],{"class":41,"line":179},[39,1170,188],{"class":108},[39,1172,1173],{"class":41,"line":185},[39,1174,65],{"emptyLinePlaceholder":64},[39,1176,1177],{"class":41,"line":191},[39,1178,1179],{"class":45},"\u002F\u002F ✓ Correct: rethrow (preserves the original stack trace).\n",[39,1181,1182,1184,1186,1188,1190,1193,1195,1197],{"class":41,"line":196},[39,1183,863],{"class":112},[39,1185,116],{"class":108},[39,1187,101],{"class":100},[39,1189,870],{"class":108},[39,1191,1192],{"class":104},"goodHandler",[39,1194,876],{"class":108},[39,1196,879],{"class":100},[39,1198,131],{"class":108},[39,1200,1201,1203],{"class":41,"line":202},[39,1202,128],{"class":100},[39,1204,131],{"class":108},[39,1206,1207,1209,1211],{"class":41,"line":220},[39,1208,894],{"class":100},[39,1210,1136],{"class":104},[39,1212,900],{"class":108},[39,1214,1215,1217,1219],{"class":41,"line":227},[39,1216,158],{"class":108},[39,1218,161],{"class":100},[39,1220,1221],{"class":108}," (e, stackTrace) {\n",[39,1223,1224,1226],{"class":41,"line":247},[39,1225,1151],{"class":104},[39,1227,1228],{"class":108},"(e, stackTrace);\n",[39,1230,1231,1234,1237],{"class":41,"line":256},[39,1232,1233],{"class":100},"    rethrow",[39,1235,1236],{"class":108},";  ",[39,1238,1239],{"class":45},"\u002F\u002F ← preserves the original throw location\n",[39,1241,1242],{"class":41,"line":272},[39,1243,182],{"class":108},[39,1245,1246],{"class":41,"line":278},[39,1247,188],{"class":108},[39,1249,1250],{"class":41,"line":287},[39,1251,65],{"emptyLinePlaceholder":64},[39,1253,1254],{"class":41,"line":292},[39,1255,1256],{"class":45},"\u002F\u002F Capturing the stack trace explicitly:\n",[39,1258,1259,1261,1263,1265,1267,1270,1272,1274],{"class":41,"line":298},[39,1260,863],{"class":112},[39,1262,116],{"class":108},[39,1264,101],{"class":100},[39,1266,870],{"class":108},[39,1268,1269],{"class":104},"withStackTrace",[39,1271,876],{"class":108},[39,1273,879],{"class":100},[39,1275,131],{"class":108},[39,1277,1278,1280],{"class":41,"line":303},[39,1279,128],{"class":100},[39,1281,131],{"class":108},[39,1283,1284,1286,1288],{"class":41,"line":308},[39,1285,894],{"class":100},[39,1287,1136],{"class":104},[39,1289,900],{"class":108},[39,1291,1292,1294,1296,1299,1301],{"class":41,"line":314},[39,1293,158],{"class":108},[39,1295,261],{"class":100},[39,1297,1298],{"class":112}," SpecificException",[39,1300,267],{"class":100},[39,1302,1221],{"class":108},[39,1304,1305],{"class":41,"line":320},[39,1306,1307],{"class":45},"    \u002F\u002F `stackTrace` is the original stack — log it for debugging.\n",[39,1309,1310,1313,1316],{"class":41,"line":326},[39,1311,1312],{"class":108},"    logger.",[39,1314,1315],{"class":104},"error",[39,1317,1228],{"class":108},[39,1319,1320,1322],{"class":41,"line":332},[39,1321,1233],{"class":100},[39,1323,1324],{"class":108},";\n",[39,1326,1327,1329,1331],{"class":41,"line":338},[39,1328,158],{"class":108},[39,1330,161],{"class":100},[39,1332,164],{"class":108},[39,1334,1335],{"class":41,"line":344},[39,1336,1337],{"class":45},"    \u002F\u002F No stack trace variable — use rethrow to preserve it.\n",[39,1339,1340,1342],{"class":41,"line":350},[39,1341,1233],{"class":100},[39,1343,1324],{"class":108},[39,1345,1346],{"class":41,"line":356},[39,1347,182],{"class":108},[39,1349,1350],{"class":41,"line":807},[39,1351,188],{"class":108},[14,1353,1355],{"id":1354},"catch-order-specific-to-broad","Catch Order — Specific to Broad",[27,1357,1358],{"language":29},[31,1359,1361],{"className":33,"code":1360,"language":29,"meta":35,"style":35},"\u002F\u002F `on` clauses are checked TOP-TO-BOTTOM. More specific types MUST come first.\n\u002F\u002F If a broader type is first, specific types below it are unreachable.\n\ntry {\n  await operation();\n} on UserNotFoundException catch (e) {\n  \u002F\u002F ✓ specific — caught here\n  handleUserNotFound(e);\n} on NotFoundException catch (e) {\n  \u002F\u002F ✓ broader — caught here (if not UserNotFoundException)\n  handleNotFound(e);\n} on HttpException catch (e) {\n  \u002F\u002F ✓ even broader\n  handleHttpError(e);\n} on Exception catch (e) {\n  \u002F\u002F ✓ broadest exception — last resort\n  handleGenericException(e);\n} catch (e, stackTrace) {\n  \u002F\u002F ✓ catches EVERYTHING (including non-Exception throwables like Error)\n  \u002F\u002F Use as a last resort with logging + rethrow.\n  logger.error('Unexpected: $e', stackTrace);\n  rethrow;\n}\n\n\u002F\u002F ❌ Anti-pattern: broad catch first — specific catches are unreachable.\ntry {\n  await operation();\n} on Exception catch (e) {\n  \u002F\u002F catches ALL exceptions — UserNotFoundException below is unreachable\n} on UserNotFoundException catch (e) {\n  \u002F\u002F ✗ dead code — never reached\n}\n",[18,1362,1363,1368,1373,1377,1384,1394,1408,1413,1420,1433,1438,1445,1457,1462,1469,1481,1486,1493,1501,1506,1511,1532,1539,1543,1547,1552,1558,1566,1578,1583,1595,1600],{"__ignoreMap":35},[39,1364,1365],{"class":41,"line":42},[39,1366,1367],{"class":45},"\u002F\u002F `on` clauses are checked TOP-TO-BOTTOM. More specific types MUST come first.\n",[39,1369,1370],{"class":41,"line":49},[39,1371,1372],{"class":45},"\u002F\u002F If a broader type is first, specific types below it are unreachable.\n",[39,1374,1375],{"class":41,"line":55},[39,1376,65],{"emptyLinePlaceholder":64},[39,1378,1379,1382],{"class":41,"line":61},[39,1380,1381],{"class":100},"try",[39,1383,131],{"class":108},[39,1385,1386,1389,1392],{"class":41,"line":68},[39,1387,1388],{"class":100},"  await",[39,1390,1391],{"class":104}," operation",[39,1393,900],{"class":108},[39,1395,1396,1399,1401,1404,1406],{"class":41,"line":74},[39,1397,1398],{"class":108},"} ",[39,1400,261],{"class":100},[39,1402,1403],{"class":112}," UserNotFoundException",[39,1405,267],{"class":100},[39,1407,164],{"class":108},[39,1409,1410],{"class":41,"line":80},[39,1411,1412],{"class":45},"  \u002F\u002F ✓ specific — caught here\n",[39,1414,1415,1418],{"class":41,"line":86},[39,1416,1417],{"class":104},"  handleUserNotFound",[39,1419,284],{"class":108},[39,1421,1422,1424,1426,1429,1431],{"class":41,"line":91},[39,1423,1398],{"class":108},[39,1425,261],{"class":100},[39,1427,1428],{"class":112}," NotFoundException",[39,1430,267],{"class":100},[39,1432,164],{"class":108},[39,1434,1435],{"class":41,"line":97},[39,1436,1437],{"class":45},"  \u002F\u002F ✓ broader — caught here (if not UserNotFoundException)\n",[39,1439,1440,1443],{"class":41,"line":125},[39,1441,1442],{"class":104},"  handleNotFound",[39,1444,284],{"class":108},[39,1446,1447,1449,1451,1453,1455],{"class":41,"line":134},[39,1448,1398],{"class":108},[39,1450,261],{"class":100},[39,1452,264],{"class":112},[39,1454,267],{"class":100},[39,1456,164],{"class":108},[39,1458,1459],{"class":41,"line":155},[39,1460,1461],{"class":45},"  \u002F\u002F ✓ even broader\n",[39,1463,1464,1467],{"class":41,"line":167},[39,1465,1466],{"class":104},"  handleHttpError",[39,1468,284],{"class":108},[39,1470,1471,1473,1475,1477,1479],{"class":41,"line":173},[39,1472,1398],{"class":108},[39,1474,261],{"class":100},[39,1476,398],{"class":112},[39,1478,267],{"class":100},[39,1480,164],{"class":108},[39,1482,1483],{"class":41,"line":179},[39,1484,1485],{"class":45},"  \u002F\u002F ✓ broadest exception — last resort\n",[39,1487,1488,1491],{"class":41,"line":185},[39,1489,1490],{"class":104},"  handleGenericException",[39,1492,284],{"class":108},[39,1494,1495,1497,1499],{"class":41,"line":191},[39,1496,1398],{"class":108},[39,1498,161],{"class":100},[39,1500,1221],{"class":108},[39,1502,1503],{"class":41,"line":196},[39,1504,1505],{"class":45},"  \u002F\u002F ✓ catches EVERYTHING (including non-Exception throwables like Error)\n",[39,1507,1508],{"class":41,"line":202},[39,1509,1510],{"class":45},"  \u002F\u002F Use as a last resort with logging + rethrow.\n",[39,1512,1513,1516,1518,1520,1523,1525,1527,1529],{"class":41,"line":220},[39,1514,1515],{"class":108},"  logger.",[39,1517,1315],{"class":104},[39,1519,109],{"class":108},[39,1521,1522],{"class":551},"'Unexpected: ",[39,1524,555],{"class":551},[39,1526,986],{"class":112},[39,1528,561],{"class":551},[39,1530,1531],{"class":108},", stackTrace);\n",[39,1533,1534,1537],{"class":41,"line":227},[39,1535,1536],{"class":100},"  rethrow",[39,1538,1324],{"class":108},[39,1540,1541],{"class":41,"line":247},[39,1542,188],{"class":108},[39,1544,1545],{"class":41,"line":256},[39,1546,65],{"emptyLinePlaceholder":64},[39,1548,1549],{"class":41,"line":272},[39,1550,1551],{"class":45},"\u002F\u002F ❌ Anti-pattern: broad catch first — specific catches are unreachable.\n",[39,1553,1554,1556],{"class":41,"line":278},[39,1555,1381],{"class":100},[39,1557,131],{"class":108},[39,1559,1560,1562,1564],{"class":41,"line":287},[39,1561,1388],{"class":100},[39,1563,1391],{"class":104},[39,1565,900],{"class":108},[39,1567,1568,1570,1572,1574,1576],{"class":41,"line":292},[39,1569,1398],{"class":108},[39,1571,261],{"class":100},[39,1573,398],{"class":112},[39,1575,267],{"class":100},[39,1577,164],{"class":108},[39,1579,1580],{"class":41,"line":298},[39,1581,1582],{"class":45},"  \u002F\u002F catches ALL exceptions — UserNotFoundException below is unreachable\n",[39,1584,1585,1587,1589,1591,1593],{"class":41,"line":303},[39,1586,1398],{"class":108},[39,1588,261],{"class":100},[39,1590,1403],{"class":112},[39,1592,267],{"class":100},[39,1594,164],{"class":108},[39,1596,1597],{"class":41,"line":308},[39,1598,1599],{"class":45},"  \u002F\u002F ✗ dead code — never reached\n",[39,1601,1602],{"class":41,"line":314},[39,1603,188],{"class":108},[14,1605,1607],{"id":1606},"the-swallow-trap-never-catch-what-you-cant-handle","The Swallow Trap — Never Catch What You Can't Handle",[27,1609,1610],{"language":29},[31,1611,1613],{"className":33,"code":1612,"language":29,"meta":35,"style":35},"\u002F\u002F ❌ Anti-pattern: catch (e) swallows everything — hides bugs.\nFuture\u003Cvoid> processBad() async {\n  try {\n    var data = await fetchData();\n    var parsed = parseData(data);  \u002F\u002F has a bug, throws StateError\n    save(parsed);\n  } catch (e) {\n    print('Something went wrong');  \u002F\u002F StateError (bug) is swallowed\n    \u002F\u002F The bug is invisible. No stack trace, no type, no way to debug.\n  }\n}\n\n\u002F\u002F ✓ Correct: catch specific recoverable exceptions, let bugs propagate.\nFuture\u003Cvoid> processGood() async {\n  try {\n    var data = await fetchData();\n    var parsed = parseData(data);\n    save(parsed);\n  } on HttpException catch (e) {\n    \u002F\u002F Recover from network issues (retry, cache, show user).\n    showRetryDialog(e);\n  } on FormatException catch (e) {\n    \u002F\u002F Recover from bad data format.\n    showFormatError(e);\n  }\n  \u002F\u002F StateError (a bug in parseData) propagates — crashes with a stack trace,\n  \u002F\u002F visible in logs, fixable. Don't swallow what you can't handle.\n}\n\n\u002F\u002F Acceptable broad catch — ONLY if you log and rethrow:\nFuture\u003Cvoid> processWithLogging() async {\n  try {\n    await operation();\n  } catch (e, stackTrace) {\n    logger.error('Unexpected error', stackTrace);\n    rethrow;  \u002F\u002F ← ALWAYS rethrow after logging a broad catch\n  }\n}\n",[18,1614,1615,1620,1639,1645,1661,1679,1687,1695,1711,1716,1720,1724,1728,1733,1752,1758,1772,1784,1790,1802,1807,1813,1826,1831,1838,1842,1847,1852,1856,1860,1865,1884,1890,1898,1906,1919,1928,1932],{"__ignoreMap":35},[39,1616,1617],{"class":41,"line":42},[39,1618,1619],{"class":45},"\u002F\u002F ❌ Anti-pattern: catch (e) swallows everything — hides bugs.\n",[39,1621,1622,1624,1626,1628,1630,1633,1635,1637],{"class":41,"line":49},[39,1623,863],{"class":112},[39,1625,116],{"class":108},[39,1627,101],{"class":100},[39,1629,870],{"class":108},[39,1631,1632],{"class":104},"processBad",[39,1634,876],{"class":108},[39,1636,879],{"class":100},[39,1638,131],{"class":108},[39,1640,1641,1643],{"class":41,"line":55},[39,1642,128],{"class":100},[39,1644,131],{"class":108},[39,1646,1647,1650,1652,1654,1657,1659],{"class":41,"line":61},[39,1648,1649],{"class":100},"    var",[39,1651,233],{"class":108},[39,1653,236],{"class":100},[39,1655,1656],{"class":100}," await",[39,1658,239],{"class":104},[39,1660,900],{"class":108},[39,1662,1663,1665,1668,1670,1673,1676],{"class":41,"line":68},[39,1664,1649],{"class":100},[39,1666,1667],{"class":108}," parsed ",[39,1669,236],{"class":100},[39,1671,1672],{"class":104}," parseData",[39,1674,1675],{"class":108},"(data);  ",[39,1677,1678],{"class":45},"\u002F\u002F has a bug, throws StateError\n",[39,1680,1681,1684],{"class":41,"line":74},[39,1682,1683],{"class":104},"    save",[39,1685,1686],{"class":108},"(parsed);\n",[39,1688,1689,1691,1693],{"class":41,"line":80},[39,1690,158],{"class":108},[39,1692,161],{"class":100},[39,1694,164],{"class":108},[39,1696,1697,1700,1702,1705,1708],{"class":41,"line":86},[39,1698,1699],{"class":104},"    print",[39,1701,109],{"class":108},[39,1703,1704],{"class":551},"'Something went wrong'",[39,1706,1707],{"class":108},");  ",[39,1709,1710],{"class":45},"\u002F\u002F StateError (bug) is swallowed\n",[39,1712,1713],{"class":41,"line":91},[39,1714,1715],{"class":45},"    \u002F\u002F The bug is invisible. No stack trace, no type, no way to debug.\n",[39,1717,1718],{"class":41,"line":97},[39,1719,182],{"class":108},[39,1721,1722],{"class":41,"line":125},[39,1723,188],{"class":108},[39,1725,1726],{"class":41,"line":134},[39,1727,65],{"emptyLinePlaceholder":64},[39,1729,1730],{"class":41,"line":155},[39,1731,1732],{"class":45},"\u002F\u002F ✓ Correct: catch specific recoverable exceptions, let bugs propagate.\n",[39,1734,1735,1737,1739,1741,1743,1746,1748,1750],{"class":41,"line":167},[39,1736,863],{"class":112},[39,1738,116],{"class":108},[39,1740,101],{"class":100},[39,1742,870],{"class":108},[39,1744,1745],{"class":104},"processGood",[39,1747,876],{"class":108},[39,1749,879],{"class":100},[39,1751,131],{"class":108},[39,1753,1754,1756],{"class":41,"line":173},[39,1755,128],{"class":100},[39,1757,131],{"class":108},[39,1759,1760,1762,1764,1766,1768,1770],{"class":41,"line":179},[39,1761,1649],{"class":100},[39,1763,233],{"class":108},[39,1765,236],{"class":100},[39,1767,1656],{"class":100},[39,1769,239],{"class":104},[39,1771,900],{"class":108},[39,1773,1774,1776,1778,1780,1782],{"class":41,"line":185},[39,1775,1649],{"class":100},[39,1777,1667],{"class":108},[39,1779,236],{"class":100},[39,1781,1672],{"class":104},[39,1783,253],{"class":108},[39,1785,1786,1788],{"class":41,"line":191},[39,1787,1683],{"class":104},[39,1789,1686],{"class":108},[39,1791,1792,1794,1796,1798,1800],{"class":41,"line":196},[39,1793,158],{"class":108},[39,1795,261],{"class":100},[39,1797,264],{"class":112},[39,1799,267],{"class":100},[39,1801,164],{"class":108},[39,1803,1804],{"class":41,"line":202},[39,1805,1806],{"class":45},"    \u002F\u002F Recover from network issues (retry, cache, show user).\n",[39,1808,1809,1811],{"class":41,"line":220},[39,1810,281],{"class":104},[39,1812,284],{"class":108},[39,1814,1815,1817,1819,1822,1824],{"class":41,"line":227},[39,1816,158],{"class":108},[39,1818,261],{"class":100},[39,1820,1821],{"class":112}," FormatException",[39,1823,267],{"class":100},[39,1825,164],{"class":108},[39,1827,1828],{"class":41,"line":247},[39,1829,1830],{"class":45},"    \u002F\u002F Recover from bad data format.\n",[39,1832,1833,1836],{"class":41,"line":256},[39,1834,1835],{"class":104},"    showFormatError",[39,1837,284],{"class":108},[39,1839,1840],{"class":41,"line":272},[39,1841,182],{"class":108},[39,1843,1844],{"class":41,"line":278},[39,1845,1846],{"class":45},"  \u002F\u002F StateError (a bug in parseData) propagates — crashes with a stack trace,\n",[39,1848,1849],{"class":41,"line":287},[39,1850,1851],{"class":45},"  \u002F\u002F visible in logs, fixable. Don't swallow what you can't handle.\n",[39,1853,1854],{"class":41,"line":292},[39,1855,188],{"class":108},[39,1857,1858],{"class":41,"line":298},[39,1859,65],{"emptyLinePlaceholder":64},[39,1861,1862],{"class":41,"line":303},[39,1863,1864],{"class":45},"\u002F\u002F Acceptable broad catch — ONLY if you log and rethrow:\n",[39,1866,1867,1869,1871,1873,1875,1878,1880,1882],{"class":41,"line":308},[39,1868,863],{"class":112},[39,1870,116],{"class":108},[39,1872,101],{"class":100},[39,1874,870],{"class":108},[39,1876,1877],{"class":104},"processWithLogging",[39,1879,876],{"class":108},[39,1881,879],{"class":100},[39,1883,131],{"class":108},[39,1885,1886,1888],{"class":41,"line":314},[39,1887,128],{"class":100},[39,1889,131],{"class":108},[39,1891,1892,1894,1896],{"class":41,"line":320},[39,1893,894],{"class":100},[39,1895,1391],{"class":104},[39,1897,900],{"class":108},[39,1899,1900,1902,1904],{"class":41,"line":326},[39,1901,158],{"class":108},[39,1903,161],{"class":100},[39,1905,1221],{"class":108},[39,1907,1908,1910,1912,1914,1917],{"class":41,"line":332},[39,1909,1312],{"class":108},[39,1911,1315],{"class":104},[39,1913,109],{"class":108},[39,1915,1916],{"class":551},"'Unexpected error'",[39,1918,1531],{"class":108},[39,1920,1921,1923,1925],{"class":41,"line":338},[39,1922,1233],{"class":100},[39,1924,1236],{"class":108},[39,1926,1927],{"class":45},"\u002F\u002F ← ALWAYS rethrow after logging a broad catch\n",[39,1929,1930],{"class":41,"line":344},[39,1931,182],{"class":108},[39,1933,1934],{"class":41,"line":350},[39,1935,188],{"class":108},[14,1937,1939],{"id":1938},"async-error-propagation-zones","Async Error Propagation & Zones",[27,1941,1942],{"language":29},[31,1943,1945],{"className":33,"code":1944,"language":29,"meta":35,"style":35},"import 'dart:async';\n\n\u002F\u002F ── try\u002Fcatch works with await — the Future's error is caught. ──\nFuture\u003Cvoid> asyncCatch() async {\n  try {\n    var data = await fetchData();  \u002F\u002F throws → caught by try\u002Fcatch\n  } on HttpException catch (e) {\n    print('Network error: $e');\n  }\n}\n\n\u002F\u002F ── Unawaited Future errors are \"uncaught in the zone.\" ──\n\u002F\u002F If a Future errors and no one awaits or catches it, the error\n\u002F\u002F propagates to the zone's uncaught error handler.\n\nvoid bad() {\n  Future.error('boom');  \u002F\u002F ← unawaited, uncaught → crashes or silent\n}\n\nvoid good() {\n  \u002F\u002F Option 1: await it (in an async function).\n  \u002F\u002F Option 2: catchError on the future.\n  Future.error('boom').catchError((e) => print('Handled: $e'));\n  \u002F\u002F Option 3: unawaited to suppress lint (if you handle errors).\n  unawaited(\n    Future.error('boom').catchError((e) => print('Handled: $e')),\n  );\n}\n\n\u002F\u002F ── runZonedGuarded: top-level boundary for uncaught async errors. ──\nvoid main() {\n  runZonedGuarded(() async {\n    \u002F\u002F All async errors in this zone are caught by the handler.\n    await runApp();\n  }, (error, stack) {\n    \u002F\u002F Last-resort error handler — log to Sentry, Crashlytics, etc.\n    logger.fatal('Uncaught async error: $error', stack);\n  });\n}\n\n\u002F\u002F ── Future.catchError vs try\u002Fcatch ──\n\u002F\u002F Prefer try\u002Fcatch with await (clearer, type-safe). catchError is for .then() chains:\nfetchData()\n    .then((data) => processData(data))\n    .catchError((e) => handle(e));  \u002F\u002F catches errors from then chain\n",[18,1946,1947,1957,1961,1966,1985,1991,2008,2020,2037,2041,2045,2049,2054,2059,2064,2068,2076,2095,2099,2103,2111,2116,2121,2162,2167,2174,2210,2215,2219,2223,2228,2237,2249,2254,2263,2268,2273,2294,2298,2302,2306,2311,2316,2324,2343],{"__ignoreMap":35},[39,1948,1949,1952,1955],{"class":41,"line":42},[39,1950,1951],{"class":100},"import",[39,1953,1954],{"class":551}," 'dart:async'",[39,1956,1324],{"class":108},[39,1958,1959],{"class":41,"line":49},[39,1960,65],{"emptyLinePlaceholder":64},[39,1962,1963],{"class":41,"line":55},[39,1964,1965],{"class":45},"\u002F\u002F ── try\u002Fcatch works with await — the Future's error is caught. ──\n",[39,1967,1968,1970,1972,1974,1976,1979,1981,1983],{"class":41,"line":61},[39,1969,863],{"class":112},[39,1971,116],{"class":108},[39,1973,101],{"class":100},[39,1975,870],{"class":108},[39,1977,1978],{"class":104},"asyncCatch",[39,1980,876],{"class":108},[39,1982,879],{"class":100},[39,1984,131],{"class":108},[39,1986,1987,1989],{"class":41,"line":68},[39,1988,128],{"class":100},[39,1990,131],{"class":108},[39,1992,1993,1995,1997,1999,2001,2003,2005],{"class":41,"line":74},[39,1994,1649],{"class":100},[39,1996,233],{"class":108},[39,1998,236],{"class":100},[39,2000,1656],{"class":100},[39,2002,239],{"class":104},[39,2004,149],{"class":108},[39,2006,2007],{"class":45},"\u002F\u002F throws → caught by try\u002Fcatch\n",[39,2009,2010,2012,2014,2016,2018],{"class":41,"line":80},[39,2011,158],{"class":108},[39,2013,261],{"class":100},[39,2015,264],{"class":112},[39,2017,267],{"class":100},[39,2019,164],{"class":108},[39,2021,2022,2024,2026,2029,2031,2033,2035],{"class":41,"line":86},[39,2023,1699],{"class":104},[39,2025,109],{"class":108},[39,2027,2028],{"class":551},"'Network error: ",[39,2030,555],{"class":551},[39,2032,986],{"class":112},[39,2034,561],{"class":551},[39,2036,599],{"class":108},[39,2038,2039],{"class":41,"line":91},[39,2040,182],{"class":108},[39,2042,2043],{"class":41,"line":97},[39,2044,188],{"class":108},[39,2046,2047],{"class":41,"line":125},[39,2048,65],{"emptyLinePlaceholder":64},[39,2050,2051],{"class":41,"line":134},[39,2052,2053],{"class":45},"\u002F\u002F ── Unawaited Future errors are \"uncaught in the zone.\" ──\n",[39,2055,2056],{"class":41,"line":155},[39,2057,2058],{"class":45},"\u002F\u002F If a Future errors and no one awaits or catches it, the error\n",[39,2060,2061],{"class":41,"line":167},[39,2062,2063],{"class":45},"\u002F\u002F propagates to the zone's uncaught error handler.\n",[39,2065,2066],{"class":41,"line":173},[39,2067,65],{"emptyLinePlaceholder":64},[39,2069,2070,2072,2074],{"class":41,"line":179},[39,2071,101],{"class":100},[39,2073,105],{"class":104},[39,2075,529],{"class":108},[39,2077,2078,2081,2083,2085,2087,2090,2092],{"class":41,"line":185},[39,2079,2080],{"class":112},"  Future",[39,2082,989],{"class":108},[39,2084,1315],{"class":104},[39,2086,109],{"class":108},[39,2088,2089],{"class":551},"'boom'",[39,2091,1707],{"class":108},[39,2093,2094],{"class":45},"\u002F\u002F ← unawaited, uncaught → crashes or silent\n",[39,2096,2097],{"class":41,"line":191},[39,2098,188],{"class":108},[39,2100,2101],{"class":41,"line":196},[39,2102,65],{"emptyLinePlaceholder":64},[39,2104,2105,2107,2109],{"class":41,"line":202},[39,2106,101],{"class":100},[39,2108,207],{"class":104},[39,2110,529],{"class":108},[39,2112,2113],{"class":41,"line":220},[39,2114,2115],{"class":45},"  \u002F\u002F Option 1: await it (in an async function).\n",[39,2117,2118],{"class":41,"line":227},[39,2119,2120],{"class":45},"  \u002F\u002F Option 2: catchError on the future.\n",[39,2122,2123,2125,2127,2129,2131,2133,2136,2139,2142,2145,2148,2150,2153,2155,2157,2159],{"class":41,"line":247},[39,2124,2080],{"class":112},[39,2126,989],{"class":108},[39,2128,1315],{"class":104},[39,2130,109],{"class":108},[39,2132,2089],{"class":551},[39,2134,2135],{"class":108},").",[39,2137,2138],{"class":104},"catchError",[39,2140,2141],{"class":108},"((e) ",[39,2143,2144],{"class":100},"=>",[39,2146,2147],{"class":104}," print",[39,2149,109],{"class":108},[39,2151,2152],{"class":551},"'Handled: ",[39,2154,555],{"class":551},[39,2156,986],{"class":112},[39,2158,561],{"class":551},[39,2160,2161],{"class":108},"));\n",[39,2163,2164],{"class":41,"line":256},[39,2165,2166],{"class":45},"  \u002F\u002F Option 3: unawaited to suppress lint (if you handle errors).\n",[39,2168,2169,2172],{"class":41,"line":272},[39,2170,2171],{"class":104},"  unawaited",[39,2173,475],{"class":108},[39,2175,2176,2179,2181,2183,2185,2187,2189,2191,2193,2195,2197,2199,2201,2203,2205,2207],{"class":41,"line":278},[39,2177,2178],{"class":112},"    Future",[39,2180,989],{"class":108},[39,2182,1315],{"class":104},[39,2184,109],{"class":108},[39,2186,2089],{"class":551},[39,2188,2135],{"class":108},[39,2190,2138],{"class":104},[39,2192,2141],{"class":108},[39,2194,2144],{"class":100},[39,2196,2147],{"class":104},[39,2198,109],{"class":108},[39,2200,2152],{"class":551},[39,2202,555],{"class":551},[39,2204,986],{"class":112},[39,2206,561],{"class":551},[39,2208,2209],{"class":108},")),\n",[39,2211,2212],{"class":41,"line":287},[39,2213,2214],{"class":108},"  );\n",[39,2216,2217],{"class":41,"line":292},[39,2218,188],{"class":108},[39,2220,2221],{"class":41,"line":298},[39,2222,65],{"emptyLinePlaceholder":64},[39,2224,2225],{"class":41,"line":303},[39,2226,2227],{"class":45},"\u002F\u002F ── runZonedGuarded: top-level boundary for uncaught async errors. ──\n",[39,2229,2230,2232,2235],{"class":41,"line":308},[39,2231,101],{"class":100},[39,2233,2234],{"class":104}," main",[39,2236,529],{"class":108},[39,2238,2239,2242,2245,2247],{"class":41,"line":314},[39,2240,2241],{"class":104},"  runZonedGuarded",[39,2243,2244],{"class":108},"(() ",[39,2246,879],{"class":100},[39,2248,131],{"class":108},[39,2250,2251],{"class":41,"line":320},[39,2252,2253],{"class":45},"    \u002F\u002F All async errors in this zone are caught by the handler.\n",[39,2255,2256,2258,2261],{"class":41,"line":326},[39,2257,894],{"class":100},[39,2259,2260],{"class":104}," runApp",[39,2262,900],{"class":108},[39,2264,2265],{"class":41,"line":332},[39,2266,2267],{"class":108},"  }, (error, stack) {\n",[39,2269,2270],{"class":41,"line":338},[39,2271,2272],{"class":45},"    \u002F\u002F Last-resort error handler — log to Sentry, Crashlytics, etc.\n",[39,2274,2275,2277,2280,2282,2285,2287,2289,2291],{"class":41,"line":344},[39,2276,1312],{"class":108},[39,2278,2279],{"class":104},"fatal",[39,2281,109],{"class":108},[39,2283,2284],{"class":551},"'Uncaught async error: ",[39,2286,555],{"class":551},[39,2288,1315],{"class":112},[39,2290,561],{"class":551},[39,2292,2293],{"class":108},", stack);\n",[39,2295,2296],{"class":41,"line":350},[39,2297,509],{"class":108},[39,2299,2300],{"class":41,"line":356},[39,2301,188],{"class":108},[39,2303,2304],{"class":41,"line":807},[39,2305,65],{"emptyLinePlaceholder":64},[39,2307,2308],{"class":41,"line":812},[39,2309,2310],{"class":45},"\u002F\u002F ── Future.catchError vs try\u002Fcatch ──\n",[39,2312,2313],{"class":41,"line":817},[39,2314,2315],{"class":45},"\u002F\u002F Prefer try\u002Fcatch with await (clearer, type-safe). catchError is for .then() chains:\n",[39,2317,2318,2321],{"class":41,"line":831},[39,2319,2320],{"class":104},"fetchData",[39,2322,2323],{"class":108},"()\n",[39,2325,2326,2329,2332,2335,2337,2340],{"class":41,"line":844},[39,2327,2328],{"class":108},"    .",[39,2330,2331],{"class":104},"then",[39,2333,2334],{"class":108},"((data) ",[39,2336,2144],{"class":100},[39,2338,2339],{"class":104}," processData",[39,2341,2342],{"class":108},"(data))\n",[39,2344,2345,2347,2349,2351,2353,2356,2359],{"class":41,"line":849},[39,2346,2328],{"class":108},[39,2348,2138],{"class":104},[39,2350,2141],{"class":108},[39,2352,2144],{"class":100},[39,2354,2355],{"class":104}," handle",[39,2357,2358],{"class":108},"(e));  ",[39,2360,2361],{"class":45},"\u002F\u002F catches errors from then chain\n",[14,2363,2365,2368],{"id":2364},"finally-cleanup-semantics",[18,2366,2367],{},"finally"," — Cleanup Semantics",[27,2370,2371],{"language":29},[31,2372,2374],{"className":33,"code":2373,"language":29,"meta":35,"style":35},"\u002F\u002F `finally` runs ALWAYS — on success, on exception, on return, on rethrow.\n\u002F\u002F Use for resource cleanup (closing connections, releasing locks).\n\nFuture\u003CString> readFile(String path) async {\n  final file = File(path);\n  final stream = file.openRead();\n  try {\n    final contents = await stream.transform(utf8.decoder).join();\n    return contents;\n  } catch (e) {\n    log('Read failed: $e');\n    rethrow;\n  } finally {\n    \u002F\u002F Runs whether the try succeeded, threw, or rethrew.\n    await stream.drain();  \u002F\u002F ensure stream is fully consumed\u002Fclosed\n  }\n}\n\n\u002F\u002F ❌ Anti-pattern: heavy logic in finally — can mask exceptions.\nFuture\u003Cvoid> badFinally() async {\n  try {\n    await risky();\n  } finally {\n    await cleanup();  \u002F\u002F if cleanup() throws, the original error is MASKED\n  }\n}\n\n\u002F\u002F ✓ Correct: keep finally minimal, handle cleanup errors separately.\nFuture\u003Cvoid> goodFinally() async {\n  try {\n    await risky();\n  } finally {\n    try {\n      await cleanup();\n    } catch (e) {\n      log('Cleanup failed: $e');  \u002F\u002F log but don't throw — don't mask original error\n    }\n  }\n}\n",[18,2375,2376,2381,2386,2390,2414,2429,2446,2452,2476,2483,2491,2508,2514,2522,2527,2541,2545,2549,2553,2558,2577,2583,2592,2600,2612,2616,2620,2624,2629,2648,2654,2662,2670,2677,2686,2695,2716,2721,2725],{"__ignoreMap":35},[39,2377,2378],{"class":41,"line":42},[39,2379,2380],{"class":45},"\u002F\u002F `finally` runs ALWAYS — on success, on exception, on return, on rethrow.\n",[39,2382,2383],{"class":41,"line":49},[39,2384,2385],{"class":45},"\u002F\u002F Use for resource cleanup (closing connections, releasing locks).\n",[39,2387,2388],{"class":41,"line":55},[39,2389,65],{"emptyLinePlaceholder":64},[39,2391,2392,2394,2396,2398,2400,2403,2405,2407,2410,2412],{"class":41,"line":61},[39,2393,863],{"class":112},[39,2395,116],{"class":108},[39,2397,447],{"class":112},[39,2399,870],{"class":108},[39,2401,2402],{"class":104},"readFile",[39,2404,109],{"class":108},[39,2406,447],{"class":112},[39,2408,2409],{"class":108}," path) ",[39,2411,879],{"class":100},[39,2413,131],{"class":108},[39,2415,2416,2418,2421,2423,2426],{"class":41,"line":68},[39,2417,405],{"class":100},[39,2419,2420],{"class":108}," file ",[39,2422,236],{"class":100},[39,2424,2425],{"class":112}," File",[39,2427,2428],{"class":108},"(path);\n",[39,2430,2431,2433,2436,2438,2441,2444],{"class":41,"line":74},[39,2432,405],{"class":100},[39,2434,2435],{"class":108}," stream ",[39,2437,236],{"class":100},[39,2439,2440],{"class":108}," file.",[39,2442,2443],{"class":104},"openRead",[39,2445,900],{"class":108},[39,2447,2448,2450],{"class":41,"line":80},[39,2449,128],{"class":100},[39,2451,131],{"class":108},[39,2453,2454,2456,2459,2461,2463,2466,2469,2472,2474],{"class":41,"line":86},[39,2455,230],{"class":100},[39,2457,2458],{"class":108}," contents ",[39,2460,236],{"class":100},[39,2462,1656],{"class":100},[39,2464,2465],{"class":108}," stream.",[39,2467,2468],{"class":104},"transform",[39,2470,2471],{"class":108},"(utf8.decoder).",[39,2473,639],{"class":104},[39,2475,900],{"class":108},[39,2477,2478,2480],{"class":41,"line":91},[39,2479,633],{"class":100},[39,2481,2482],{"class":108}," contents;\n",[39,2484,2485,2487,2489],{"class":41,"line":97},[39,2486,158],{"class":108},[39,2488,161],{"class":100},[39,2490,164],{"class":108},[39,2492,2493,2495,2497,2500,2502,2504,2506],{"class":41,"line":125},[39,2494,1151],{"class":104},[39,2496,109],{"class":108},[39,2498,2499],{"class":551},"'Read failed: ",[39,2501,555],{"class":551},[39,2503,986],{"class":112},[39,2505,561],{"class":551},[39,2507,599],{"class":108},[39,2509,2510,2512],{"class":41,"line":134},[39,2511,1233],{"class":100},[39,2513,1324],{"class":108},[39,2515,2516,2518,2520],{"class":41,"line":155},[39,2517,158],{"class":108},[39,2519,2367],{"class":100},[39,2521,131],{"class":108},[39,2523,2524],{"class":41,"line":167},[39,2525,2526],{"class":45},"    \u002F\u002F Runs whether the try succeeded, threw, or rethrew.\n",[39,2528,2529,2531,2533,2536,2538],{"class":41,"line":173},[39,2530,894],{"class":100},[39,2532,2465],{"class":108},[39,2534,2535],{"class":104},"drain",[39,2537,149],{"class":108},[39,2539,2540],{"class":45},"\u002F\u002F ensure stream is fully consumed\u002Fclosed\n",[39,2542,2543],{"class":41,"line":179},[39,2544,182],{"class":108},[39,2546,2547],{"class":41,"line":185},[39,2548,188],{"class":108},[39,2550,2551],{"class":41,"line":191},[39,2552,65],{"emptyLinePlaceholder":64},[39,2554,2555],{"class":41,"line":196},[39,2556,2557],{"class":45},"\u002F\u002F ❌ Anti-pattern: heavy logic in finally — can mask exceptions.\n",[39,2559,2560,2562,2564,2566,2568,2571,2573,2575],{"class":41,"line":202},[39,2561,863],{"class":112},[39,2563,116],{"class":108},[39,2565,101],{"class":100},[39,2567,870],{"class":108},[39,2569,2570],{"class":104},"badFinally",[39,2572,876],{"class":108},[39,2574,879],{"class":100},[39,2576,131],{"class":108},[39,2578,2579,2581],{"class":41,"line":220},[39,2580,128],{"class":100},[39,2582,131],{"class":108},[39,2584,2585,2587,2590],{"class":41,"line":227},[39,2586,894],{"class":100},[39,2588,2589],{"class":104}," risky",[39,2591,900],{"class":108},[39,2593,2594,2596,2598],{"class":41,"line":247},[39,2595,158],{"class":108},[39,2597,2367],{"class":100},[39,2599,131],{"class":108},[39,2601,2602,2604,2607,2609],{"class":41,"line":256},[39,2603,894],{"class":100},[39,2605,2606],{"class":104}," cleanup",[39,2608,149],{"class":108},[39,2610,2611],{"class":45},"\u002F\u002F if cleanup() throws, the original error is MASKED\n",[39,2613,2614],{"class":41,"line":272},[39,2615,182],{"class":108},[39,2617,2618],{"class":41,"line":278},[39,2619,188],{"class":108},[39,2621,2622],{"class":41,"line":287},[39,2623,65],{"emptyLinePlaceholder":64},[39,2625,2626],{"class":41,"line":292},[39,2627,2628],{"class":45},"\u002F\u002F ✓ Correct: keep finally minimal, handle cleanup errors separately.\n",[39,2630,2631,2633,2635,2637,2639,2642,2644,2646],{"class":41,"line":298},[39,2632,863],{"class":112},[39,2634,116],{"class":108},[39,2636,101],{"class":100},[39,2638,870],{"class":108},[39,2640,2641],{"class":104},"goodFinally",[39,2643,876],{"class":108},[39,2645,879],{"class":100},[39,2647,131],{"class":108},[39,2649,2650,2652],{"class":41,"line":303},[39,2651,128],{"class":100},[39,2653,131],{"class":108},[39,2655,2656,2658,2660],{"class":41,"line":308},[39,2657,894],{"class":100},[39,2659,2589],{"class":104},[39,2661,900],{"class":108},[39,2663,2664,2666,2668],{"class":41,"line":314},[39,2665,158],{"class":108},[39,2667,2367],{"class":100},[39,2669,131],{"class":108},[39,2671,2672,2675],{"class":41,"line":320},[39,2673,2674],{"class":100},"    try",[39,2676,131],{"class":108},[39,2678,2679,2682,2684],{"class":41,"line":326},[39,2680,2681],{"class":100},"      await",[39,2683,2606],{"class":104},[39,2685,900],{"class":108},[39,2687,2688,2691,2693],{"class":41,"line":332},[39,2689,2690],{"class":108},"    } ",[39,2692,161],{"class":100},[39,2694,164],{"class":108},[39,2696,2697,2700,2702,2705,2707,2709,2711,2713],{"class":41,"line":338},[39,2698,2699],{"class":104},"      log",[39,2701,109],{"class":108},[39,2703,2704],{"class":551},"'Cleanup failed: ",[39,2706,555],{"class":551},[39,2708,986],{"class":112},[39,2710,561],{"class":551},[39,2712,1707],{"class":108},[39,2714,2715],{"class":45},"\u002F\u002F log but don't throw — don't mask original error\n",[39,2717,2718],{"class":41,"line":344},[39,2719,2720],{"class":108},"    }\n",[39,2722,2723],{"class":41,"line":350},[39,2724,182],{"class":108},[39,2726,2727],{"class":41,"line":356},[39,2728,188],{"class":108},[14,2730,2732],{"id":2731},"tips-tricks","💡 Tips & Tricks",[2734,2735,2736,2767,2783,2799,2815],"ul",{},[2737,2738,2739,2743,2744,2746,2747,2749,2750,450,2753,2756,2757,450,2760,2763,2764,2766],"li",{},[2740,2741,2742],"strong",{},"Idiom",": throw ",[18,2745,20],{}," subtypes for recoverable conditions, ",[18,2748,24],{}," subtypes for bugs — ",[18,2751,2752],{},"HttpException",[18,2754,2755],{},"FormatException"," (recoverable, catch them); ",[18,2758,2759],{},"StateError",[18,2761,2762],{},"RangeError"," (bugs, let them crash). Don't catch ",[18,2765,24],{},"s — they indicate a code bug, not a runtime condition.",[2737,2768,2769,2771,2772,2775,2776,2779,2780,2782],{},[2740,2770,2742],{},": catch specific exceptions, not broad ",[18,2773,2774],{},"catch (e)"," — ",[18,2777,2778],{},"on HttpException catch (e)"," is clear; ",[18,2781,2774],{}," catches everything (including bugs), hiding issues. Catch what you can recover from, let the rest propagate.",[2737,2784,2785,998,2787,2789,2790,2792,2793,2795,2796,2798],{},[2740,2786,2742],{},[18,2788,1055],{}," (not ",[18,2791,1058],{},") to preserve the original stack trace — ",[18,2794,1055],{}," keeps the original throw location; ",[18,2797,1058],{}," resets the stack to the catch site. Use when logging\u002Fhandling partially but passing the error up.",[2737,2800,2801,2803,2804,2807,2808,2810,2811,2814],{},[2740,2802,2742],{},": use ",[18,2805,2806],{},"runZonedGuarded"," for uncaught async errors — errors in unawaited Futures are \"uncaught in the zone.\" ",[18,2809,2806],{}," catches them for logging\u002Frecovery. Use in ",[18,2812,2813],{},"main"," as a top-level safety net.",[2737,2816,2817,2819,2820,2823,2824,2823,2827,2830,2831,2833],{},[2740,2818,2742],{},": order catches from specific to broad — ",[18,2821,2822],{},"on UserNotFoundException"," before ",[18,2825,2826],{},"on NotFoundException",[18,2828,2829],{},"on Exception",". The first matching ",[18,2832,261],{}," clause wins; broader types first make specific catches unreachable (dead code).",[14,2835,2837],{"id":2836},"️-edge-cases-gotchas","⚠️ Edge Cases & Gotchas",[2734,2839,2840,2855,2872,2888,2912,2934,2950,2966,2988,3002],{},[2737,2841,2842,998,2845,2848,2849,2851,2852,2854],{},[2740,2843,2844],{},"Any object can be thrown",[18,2846,2847],{},"throw 'a string'"," is valid (unlike Java). But convention: throw ",[18,2850,20],{},"\u002F",[18,2853,24],{}," subtypes for catchability and clarity.",[2737,2856,2857,2862,2863,2865,2866,2868,2869,989],{},[2740,2858,2859,2861],{},[18,2860,2774],{}," is too broad",": catches everything (including ",[18,2864,24],{},"s like ",[18,2867,2762],{},"), hiding bugs. Prefer ",[18,2870,2871],{},"on SpecificType catch (e)",[2737,2873,2874,2803,2879,2881,2882,2884,2885,2887],{},[2740,2875,2876,2878],{},[18,2877,1058],{}," resets the stack trace",[18,2880,1055],{}," to preserve the original. ",[18,2883,1058],{}," makes the exception look like it originated from the ",[18,2886,1058],{}," line.",[2737,2889,2890,998,2902,2775,2905,2908,2909,2911],{},[2740,2891,2892,2894,2895,2851,2897,2851,2900],{},[18,2893,2367],{}," runs on ",[18,2896,933],{},[18,2898,2899],{},"throw",[18,2901,1055],{},[18,2903,2904],{},"try { return f(); } finally { cleanup(); }",[18,2906,2907],{},"cleanup"," runs before ",[18,2910,933],{},"'s value is returned. Keep finally minimal to avoid masking exceptions.",[2737,2913,2914,2920,2921,2924,2925,2927,2928,2851,2931,989],{},[2740,2915,2916,2919],{},[18,2917,2918],{},"assert"," is debug-only",": stripped in AOT. ",[18,2922,2923],{},"AssertionError"," only occurs in debug. Don't use ",[18,2926,2918],{}," for runtime validation — use ",[18,2929,2930],{},"if",[18,2932,2933],{},"throw ArgumentError",[2737,2935,2936,2939,2940,2943,2944,2947,2948,989],{},[2740,2937,2938],{},"Uncaught async errors crash or are silent",": unawaited Future errors are \"uncaught in the zone.\" In Flutter: red screen in debug. In CLI: may crash. Always ",[18,2941,2942],{},"await"," or ",[18,2945,2946],{},".catchError"," or use ",[18,2949,2806],{},[2737,2951,2952,998,2958,450,2960,2962,2963,2965],{},[2740,2953,2954,2955,2957],{},"Don't catch ",[18,2956,24],{},"s",[18,2959,2759],{},[18,2961,2762],{}," are bugs — catching them hides the bug. Let them crash so you find and fix the root cause. Catch ",[18,2964,20],{},"s (recoverable).",[2737,2967,2968,2974,2975,2977,2978,2980,2981,2983,2984,2987],{},[2740,2969,2970,2973],{},[18,2971,2972],{},"on Exception catch (e)"," catches all Exception subtypes",": but not ",[18,2976,24],{},"s (which extend ",[18,2979,24],{},", not ",[18,2982,20],{},"). ",[18,2985,2986],{},"catch (e, stack)"," catches everything.",[2737,2989,2990,2998,2999,3001],{},[2740,2991,2992,2995,2996],{},[18,2993,2994],{},"NoSuchMethodError"," from ",[18,2997,453],{},": calling a non-existent method on ",[18,3000,453],{}," throws at runtime (no compile check). Use typed variables to catch at compile time.",[2737,3003,3004,3009,3010,3013,3014,3017],{},[2740,3005,3006],{},[18,3007,3008],{},"ConcurrentModificationError",": modifying a collection while iterating it (e.g., ",[18,3011,3012],{},"list.remove"," inside ",[18,3015,3016],{},"for (var x in list)",") throws. Collect items to remove, then remove after the loop.",[14,3019,3021],{"id":3020},"spot-the-bug","🧠 Spot the Bug",[3023,3024,3025],"p",{},"A developer wraps their entire request handler in a broad catch to \"handle all errors gracefully\":",[27,3027,3028],{"language":29},[31,3029,3031],{"className":33,"code":3030,"language":29,"meta":35,"style":35},"Future\u003CResponse> handle(Request req) async {\n  try {\n    final body = jsonDecode(await req.readAsString());\n    final user = parseUser(body);  \u002F\u002F has a null-deref bug, throws StateError\n    return Response.ok(jsonEncode(user));\n  } catch (e) {\n    return Response(500, body: 'Internal error');\n  }\n}\n",[18,3032,3033,3059,3065,3090,3108,3128,3136,3157,3161],{"__ignoreMap":35},[39,3034,3035,3037,3039,3042,3044,3047,3049,3052,3055,3057],{"class":41,"line":42},[39,3036,863],{"class":112},[39,3038,116],{"class":108},[39,3040,3041],{"class":112},"Response",[39,3043,870],{"class":108},[39,3045,3046],{"class":104},"handle",[39,3048,109],{"class":108},[39,3050,3051],{"class":112},"Request",[39,3053,3054],{"class":108}," req) ",[39,3056,879],{"class":100},[39,3058,131],{"class":108},[39,3060,3061,3063],{"class":41,"line":49},[39,3062,128],{"class":100},[39,3064,131],{"class":108},[39,3066,3067,3069,3072,3074,3077,3079,3081,3084,3087],{"class":41,"line":55},[39,3068,230],{"class":100},[39,3070,3071],{"class":108}," body ",[39,3073,236],{"class":100},[39,3075,3076],{"class":104}," jsonDecode",[39,3078,109],{"class":108},[39,3080,2942],{"class":100},[39,3082,3083],{"class":108}," req.",[39,3085,3086],{"class":104},"readAsString",[39,3088,3089],{"class":108},"());\n",[39,3091,3092,3094,3097,3099,3102,3105],{"class":41,"line":61},[39,3093,230],{"class":100},[39,3095,3096],{"class":108}," user ",[39,3098,236],{"class":100},[39,3100,3101],{"class":104}," parseUser",[39,3103,3104],{"class":108},"(body);  ",[39,3106,3107],{"class":45},"\u002F\u002F has a null-deref bug, throws StateError\n",[39,3109,3110,3112,3115,3117,3120,3122,3125],{"class":41,"line":68},[39,3111,633],{"class":100},[39,3113,3114],{"class":112}," Response",[39,3116,989],{"class":108},[39,3118,3119],{"class":104},"ok",[39,3121,109],{"class":108},[39,3123,3124],{"class":104},"jsonEncode",[39,3126,3127],{"class":108},"(user));\n",[39,3129,3130,3132,3134],{"class":41,"line":74},[39,3131,158],{"class":108},[39,3133,161],{"class":100},[39,3135,164],{"class":108},[39,3137,3138,3140,3142,3144,3147,3150,3152,3155],{"class":41,"line":80},[39,3139,633],{"class":100},[39,3141,3114],{"class":112},[39,3143,109],{"class":108},[39,3145,3146],{"class":112},"500",[39,3148,3149],{"class":108},", body",[39,3151,977],{"class":100},[39,3153,3154],{"class":551}," 'Internal error'",[39,3156,599],{"class":108},[39,3158,3159],{"class":41,"line":86},[39,3160,182],{"class":108},[39,3162,3163],{"class":41,"line":91},[39,3164,188],{"class":108},[3023,3166,3167],{},"Why is this dangerous?",[3169,3170,3171,3175,3195,3211,3214,3217],"details",{},[3172,3173,3174],"summary",{},"Answer",[3023,3176,3177,3179,3180,3183,3184,3186,3187,3190,3191,3194],{},[18,3178,2774],{}," catches ",[2740,3181,3182],{},"everything"," — including the ",[18,3185,2759],{}," from the bug in ",[18,3188,3189],{},"parseUser",". The error is swallowed, and the client gets a generic ",[18,3192,3193],{},"500 Internal error"," response. The developer never sees:",[2734,3196,3197,3202,3205],{},[2737,3198,3199,3200,2135],{},"The exception type (",[18,3201,2759],{},[2737,3203,3204],{},"The error message (what was null? what state was wrong?).",[2737,3206,3207,3208,3210],{},"The stack trace (which line in ",[18,3209,3189],{}," threw).",[3023,3212,3213],{},"The bug is invisible in production. The 500 response tells the developer nothing. This pattern is a debugging nightmare — every bug becomes an opaque 500.",[3023,3215,3216],{},"The fix — catch specific recoverable exceptions, let bugs propagate (or catch broadly ONLY with logging + rethrow):",[31,3218,3220],{"className":33,"code":3219,"language":29,"meta":35,"style":35},"Future\u003CResponse> handle(Request req) async {\n  try {\n    final body = jsonDecode(await req.readAsString());\n    final user = parseUser(body);\n    return Response.ok(jsonEncode(user));\n  } on FormatException catch (e) {\n    \u002F\u002F Recoverable: bad JSON → 400 to the client.\n    return Response(400, body: 'Invalid JSON: ${e.message}');\n  } on ValidationException catch (e) {\n    \u002F\u002F Recoverable: bad input → 422 to the client.\n    return Response(422, body: 'Validation error: ${e.field}: ${e.message}');\n  }\n  \u002F\u002F StateError (bug in parseUser) propagates → crashes with a stack trace.\n  \u002F\u002F The developer sees the bug in logs, can fix it.\n}\n\n\u002F\u002F If you MUST catch broadly (e.g., top-level middleware), log + rethrow:\nFuture\u003CResponse> withLogging(Request req) async {\n  try {\n    return await handle(req);\n  } catch (e, stack) {\n    logger.error('Unhandled: $e', stack);\n    rethrow;  \u002F\u002F or return 500 WITH the error logged\n  }\n}\n",[18,3221,3222,3244,3250,3270,3283,3299,3311,3316,3348,3360,3365,3409,3413,3418,3423,3427,3431,3436,3459,3465,3476,3485,3504,3513,3517],{"__ignoreMap":35},[39,3223,3224,3226,3228,3230,3232,3234,3236,3238,3240,3242],{"class":41,"line":42},[39,3225,863],{"class":112},[39,3227,116],{"class":108},[39,3229,3041],{"class":112},[39,3231,870],{"class":108},[39,3233,3046],{"class":104},[39,3235,109],{"class":108},[39,3237,3051],{"class":112},[39,3239,3054],{"class":108},[39,3241,879],{"class":100},[39,3243,131],{"class":108},[39,3245,3246,3248],{"class":41,"line":49},[39,3247,128],{"class":100},[39,3249,131],{"class":108},[39,3251,3252,3254,3256,3258,3260,3262,3264,3266,3268],{"class":41,"line":55},[39,3253,230],{"class":100},[39,3255,3071],{"class":108},[39,3257,236],{"class":100},[39,3259,3076],{"class":104},[39,3261,109],{"class":108},[39,3263,2942],{"class":100},[39,3265,3083],{"class":108},[39,3267,3086],{"class":104},[39,3269,3089],{"class":108},[39,3271,3272,3274,3276,3278,3280],{"class":41,"line":61},[39,3273,230],{"class":100},[39,3275,3096],{"class":108},[39,3277,236],{"class":100},[39,3279,3101],{"class":104},[39,3281,3282],{"class":108},"(body);\n",[39,3284,3285,3287,3289,3291,3293,3295,3297],{"class":41,"line":68},[39,3286,633],{"class":100},[39,3288,3114],{"class":112},[39,3290,989],{"class":108},[39,3292,3119],{"class":104},[39,3294,109],{"class":108},[39,3296,3124],{"class":104},[39,3298,3127],{"class":108},[39,3300,3301,3303,3305,3307,3309],{"class":41,"line":74},[39,3302,158],{"class":108},[39,3304,261],{"class":100},[39,3306,1821],{"class":112},[39,3308,267],{"class":100},[39,3310,164],{"class":108},[39,3312,3313],{"class":41,"line":80},[39,3314,3315],{"class":45},"    \u002F\u002F Recoverable: bad JSON → 400 to the client.\n",[39,3317,3318,3320,3322,3324,3327,3329,3331,3334,3336,3338,3340,3342,3344,3346],{"class":41,"line":86},[39,3319,633],{"class":100},[39,3321,3114],{"class":112},[39,3323,109],{"class":108},[39,3325,3326],{"class":112},"400",[39,3328,3149],{"class":108},[39,3330,977],{"class":100},[39,3332,3333],{"class":551}," 'Invalid JSON: ",[39,3335,983],{"class":551},[39,3337,986],{"class":112},[39,3339,989],{"class":551},[39,3341,558],{"class":112},[39,3343,995],{"class":551},[39,3345,561],{"class":551},[39,3347,599],{"class":108},[39,3349,3350,3352,3354,3356,3358],{"class":41,"line":91},[39,3351,158],{"class":108},[39,3353,261],{"class":100},[39,3355,768],{"class":112},[39,3357,267],{"class":100},[39,3359,164],{"class":108},[39,3361,3362],{"class":41,"line":97},[39,3363,3364],{"class":45},"    \u002F\u002F Recoverable: bad input → 422 to the client.\n",[39,3366,3367,3369,3371,3373,3376,3378,3380,3383,3385,3387,3389,3391,3393,3395,3397,3399,3401,3403,3405,3407],{"class":41,"line":125},[39,3368,633],{"class":100},[39,3370,3114],{"class":112},[39,3372,109],{"class":108},[39,3374,3375],{"class":112},"422",[39,3377,3149],{"class":108},[39,3379,977],{"class":100},[39,3381,3382],{"class":551}," 'Validation error: ",[39,3384,983],{"class":551},[39,3386,986],{"class":112},[39,3388,989],{"class":551},[39,3390,992],{"class":112},[39,3392,995],{"class":551},[39,3394,998],{"class":551},[39,3396,983],{"class":551},[39,3398,986],{"class":112},[39,3400,989],{"class":551},[39,3402,558],{"class":112},[39,3404,995],{"class":551},[39,3406,561],{"class":551},[39,3408,599],{"class":108},[39,3410,3411],{"class":41,"line":134},[39,3412,182],{"class":108},[39,3414,3415],{"class":41,"line":155},[39,3416,3417],{"class":45},"  \u002F\u002F StateError (bug in parseUser) propagates → crashes with a stack trace.\n",[39,3419,3420],{"class":41,"line":167},[39,3421,3422],{"class":45},"  \u002F\u002F The developer sees the bug in logs, can fix it.\n",[39,3424,3425],{"class":41,"line":173},[39,3426,188],{"class":108},[39,3428,3429],{"class":41,"line":179},[39,3430,65],{"emptyLinePlaceholder":64},[39,3432,3433],{"class":41,"line":185},[39,3434,3435],{"class":45},"\u002F\u002F If you MUST catch broadly (e.g., top-level middleware), log + rethrow:\n",[39,3437,3438,3440,3442,3444,3446,3449,3451,3453,3455,3457],{"class":41,"line":191},[39,3439,863],{"class":112},[39,3441,116],{"class":108},[39,3443,3041],{"class":112},[39,3445,870],{"class":108},[39,3447,3448],{"class":104},"withLogging",[39,3450,109],{"class":108},[39,3452,3051],{"class":112},[39,3454,3054],{"class":108},[39,3456,879],{"class":100},[39,3458,131],{"class":108},[39,3460,3461,3463],{"class":41,"line":196},[39,3462,128],{"class":100},[39,3464,131],{"class":108},[39,3466,3467,3469,3471,3473],{"class":41,"line":202},[39,3468,633],{"class":100},[39,3470,1656],{"class":100},[39,3472,2355],{"class":104},[39,3474,3475],{"class":108},"(req);\n",[39,3477,3478,3480,3482],{"class":41,"line":220},[39,3479,158],{"class":108},[39,3481,161],{"class":100},[39,3483,3484],{"class":108}," (e, stack) {\n",[39,3486,3487,3489,3491,3493,3496,3498,3500,3502],{"class":41,"line":227},[39,3488,1312],{"class":108},[39,3490,1315],{"class":104},[39,3492,109],{"class":108},[39,3494,3495],{"class":551},"'Unhandled: ",[39,3497,555],{"class":551},[39,3499,986],{"class":112},[39,3501,561],{"class":551},[39,3503,2293],{"class":108},[39,3505,3506,3508,3510],{"class":41,"line":247},[39,3507,1233],{"class":100},[39,3509,1236],{"class":108},[39,3511,3512],{"class":45},"\u002F\u002F or return 500 WITH the error logged\n",[39,3514,3515],{"class":41,"line":256},[39,3516,182],{"class":108},[39,3518,3519],{"class":41,"line":272},[39,3520,188],{"class":108},[3522,3523,3524],"style",{},"html pre.shiki code .sdCPZ, html code.shiki .sdCPZ{--shiki-default:#6A737D;--shiki-github-dark:#6A737D}html pre.shiki code .svdQ7, html code.shiki .svdQ7{--shiki-default:#D73A49;--shiki-github-dark:#F97583}html pre.shiki code .sIsaT, html code.shiki .sIsaT{--shiki-default:#6F42C1;--shiki-github-dark:#B392F0}html pre.shiki code .ssxIu, html code.shiki .ssxIu{--shiki-default:#24292E;--shiki-github-dark:#E1E4E8}html pre.shiki code .snvgF, html code.shiki .snvgF{--shiki-default:#005CC5;--shiki-github-dark:#79B8FF}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 .github-dark .shiki span {color: var(--shiki-github-dark);background: var(--shiki-github-dark-bg);font-style: var(--shiki-github-dark-font-style);font-weight: var(--shiki-github-dark-font-weight);text-decoration: var(--shiki-github-dark-text-decoration);}html.github-dark .shiki span {color: var(--shiki-github-dark);background: var(--shiki-github-dark-bg);font-style: var(--shiki-github-dark-font-style);font-weight: var(--shiki-github-dark-font-weight);text-decoration: var(--shiki-github-dark-text-decoration);}html pre.shiki code .sJ6F3, html code.shiki .sJ6F3{--shiki-default:#032F62;--shiki-github-dark:#9ECBFF}",{"title":35,"searchDepth":49,"depth":49,"links":3526},[3527,3529,3530,3532,3533,3534,3535,3537,3538,3539],{"id":16,"depth":49,"text":3528},"Exception vs Error — Semantic Boundary",{"id":362,"depth":49,"text":363},{"id":1052,"depth":49,"text":3531},"rethrow vs throw e — Stack Trace Preservation",{"id":1354,"depth":49,"text":1355},{"id":1606,"depth":49,"text":1607},{"id":1938,"depth":49,"text":1939},{"id":2364,"depth":49,"text":3536},"finally — Cleanup Semantics",{"id":2731,"depth":49,"text":2732},{"id":2836,"depth":49,"text":2837},{"id":3020,"depth":49,"text":3021},"Deep-dive into Dart's exception vs error semantics, custom exception design, rethrow vs throw stack trace preservation, async error zones, and anti-patterns in catch blocks. Code-first engineering reference.","md",{},"\u002Fdart\u002F11-error-handling",{"title":5,"description":3540},"dart\u002F11-error-handling","FImKjS5vx-UGAYmiulJsmtmdoyW0594FP6lIfQVNlK4",1789924647903]