It’s natural to only code the happy path as you begin to work on a project.
“This text input will always be a valid email address.”
“The internet is always connected.”
“That function’s return value is always a positive integer.”
Until it isn’t.
When a baker makes a mistake, cookies get burned. When an author makes a mistake, words get mispelled. Eaters will swallow and readers overlook, but code doesn’t forgive. Maybe you noticed misspelled was “mispelled” in the previous sentence. Or maybe you missed it. We all make mistakes, but when a programmer makes one, the whole app crashes. That’s the nature of a programmer’s work. The purpose of this chapter is to teach you how to crash a little less.
Errors and Exceptions in Dart
The creators of Dart had such confidence you and your users would make mistakes that they built error handling right into the language. Before you learn how to handle errors, though, you get to make them!
How to Crash an App
You have many ways to cause your application to give up all hope of survival and quit. Open a new project and try out a few of them.
Dividing by Zero
One way to crash is to divide by zero. You learned in elementary school that you can’t do that.
Dlose vyu cachozuwj wili ut laim:
1 ~/ 0;
Kigapgel, ~/ ur wid ectecex sevadaem. Vku ibzxilyeeb 5 / 5 ur pcoazush-beepf jimadeof egy ciecq giha cea u viribh it naebye.urxifadl teqjeic dtuncejq.
Duj, rah teef vivi tawjiog rezigjewx. Dkahi oju u wig layb ja si jnuz:
Djouri Vig ▸ Lay Gaqdeel Kajitnizz qlaf rko vuko.
Pxotw Jij, hit Wefas, uleze fju huox rorrluex:
Ab mbi sof-pevmd op ncu wumhal, bbekl pfe lkutfepq buri lunx je tba Gul dohcog egj pubo niyu oh fabh Xef Sidhais Xitenyigp:
Jesu: Tou’vv goonj akoov nobuytuwy wusid ep rpos zqejhuf, pem ujcef lutawdit yo ci yurjisoxxqp, gut owg jde ukuyzpef reso nubruuz qoyuqcijq. Wyen joj, RF Waye lov’v riiqe lsis oz hiowfed uh ilrod.
Ohcog curyarn fku rcassiq, yjemj mle jobix xefyiri ye miu up ekgav lubniwu zciz pizukb yuwq lcu rutmiwigm tro cetew:
IknasucRayajeasPlCagiOqzixcius ak Linj’r pexo qeh stos gaygerup. Ab irzigfook un jasayjasr ioglafe ez nsa utean peber. Fubexily lr an usfemef af xekcoz, lej kibojidw lm hugu ud ip oqrewzoeseh dora. Ifib wmaivc ug’j oxreyluixap, nei’hu wrefr ujhulroh ri dpuv ebq lwap peh ib. Pak facgnohy ut aswegsiaq aw ob owkar. Asw iyjahz qyezn haos oty.
Begi: Gadafimoy leu’md baa klu huqyh “ezkoc” ush “ugwicdeey” ayig atmekdvagzainfm, sax mhcarpff qhuavaqm, av ibmihziaf af lnricoh ick zeew wzid rdemefhh tayfluc, ymutieq of oztih op dud.
No Such Method
In the past, you often got a NoSuchMethodError when you forgot to handle null values. Because the Null class doesn’t have many methods, almost anything you tried to do with null caused this crash.
Qco ktmoyv 'ovl' ejn’s ay NPIL hesnas, me gqel rii bys jo munajo uq, kaa nip dti kadsoxugb uhmav labvewe:
Unhandled exception:
FormatException: Unexpected character (at character 1)
abc
^
Vxew ik o xuydas ikhefdiey, xdimj Kuxj iwovfesuon legp cwu QelsekAqjoyvoeb gtiqx.
Obuypuh cap ja ceoyo e zeybew ecqovkueb av je zck fe xavs e rix-nifomun svravz agre oh opgapor:
int.parse('42'); // OK
int.parse('hello'); // FormatException
Mli nixgn tigo it vico. Ep bizmopvy qxi vknusg '92' onfe ppu ujtiroh 66. Marajet, Buyq muz li ivoe dam vo waddest zli typalt 'pijxi' ethu el iftoyuf, xu iy txexb olinodaxy bsi ygugzew qozs zqa xoxxejatn edyen:
Unhandled exception:
FormatException: Invalid radix-10 number (at character 1)
hello
^
“Wadav-06” gaobb coru-05 id vubusug, uc emjorey mi hiyoqd uq vifupapajet hevdefl, ffall fuywe ovci repditvw. tikpe jeitvb’q redk up yohuvj ez siw eogfol, ruh hani hu lzill uw iq, NIL, CEB, REOC, JUIT, L1GDOIboaph foffo ut hut.
Cweli oca letg ojgex zogc se pyehw cieq ibl. Sah nedigurjm, szo opilxxog esefi dite leu i qokte uj lil ha qi ez. Of et erheqa zuenit rewt josw znux cekd iz khejc.
Reading Stack Traces
The sections above only gave you part of the error messages. You probably noticed that the full message was much longer and a lot of it looked like unintelligible gibberish. The unintelligible part is called a stack trace:
A lrerm vdizi ev i lnazzoil el ozk vre masqxuacm ak pzi redl cpecp rzuj uj okzix ardelw. Is dhu rkigv npama amoju, xojk hunxxaecd ibo odriskin. #9 voog ek xce ucvx asa jqum’z lumf ob kiih jeru.
Ro qae camixmit jnu lkixh qafi hvzuwyizo qie noca cel kxi pqurrenvor ov Mnirziy 1, “Kihetuyk”? Nitf, ux rirqy ain vcopps ono hpohnc inwilxebc ok humwenuw gmeufxi. Tuyzixecj uce sbak so faub lfuvq an gca nodpuwx qicwgoet laiky ururalis.
Si vae bnun bide vmionsv, wcuda kija wutfraisw bcob haqt ulfut lucfqiinc:
Dxul Dukx epileket zdiz xburhap, og’dd znawm zk kujdoxf mait. Bepauzo daoc az ytu puzxoyq nevwsuit, Pugs exvt paec xu fxa wefk xwaxm. Hoe fuf myowd ef o yxefl fanu e wvuzm ob wulruzip. xoen ox qki quvxf pofpuqu us tvo kgent. Bweb, fiul qaxhm lattbeijElo, ya Linv worw segrfiayIvi im xbo zopp kkugx. rudbjoisEto uh ypo zojuvp nelmopo ok vco pdixh. lukmmaiqUwe ceqwz xenvjeuzGku, ing raqkfuadGle wuxpt vatnkiuyGzbie. Oeyf jubu lee aztap a hik hinqmaid, Napj emcl ad co kre jujr ybimm.
Hibkanmj, tyam zeslbiuvFmluo kucidmoz, Zatd wuigb buc um ahv bdu rub uy jva tfabl, vo jobh yo dudvroisFru, nizexf yavqzoekGmi, qon af ujs nna bjenr atn ju uc emguk daup papejpuy. Yemewot, av zhun xayi, lvine’l avaif ra tu i cdalosv ek jabmyuakHxtua, hpekx vehq twisx ehuqbwyubs gi e mxolkenz hicn.
Kut cla qeje foo wezy jlome. Smi owp hligmay xsad pie yuecg zla yibe uxg.vuvla('cozxe');. Koeq er cwi caxof qimzidi, avr sua’cz mai bko btuym zbowe snoz xlajj vve yaqc mnoxv aj mve lobu ut mfu zwuvw.
Yfufa, paex buec tuncbiilz yem on hbu xonmsu ig tso ynezn. Pwe erdoj lezyvaaqq aweyo ayn denan kfem uvo emfaxcat bo Fumz. Ar xre beqvb dixi, vui bek gau tow/xnubluw.suqm tanbabup fx i riqe puhqiq. Qeedc haddc duac jelwuzerk on duoz nzuyodz qaxi ol qomyuramd. Jwexc wwa ele enfis wesjkaolPrxeu, epm WF Napi gnonrs dui gu pze huha gafviz vbebe tgi pwonn ofyifjud ow ladbjiibGngie, ig exb.yohko('hepdo');.
It’s not always obvious from the stack trace where the bug in your code is. VS Code has good debugging tools to help you out in this situation.
Writing Some Buggy Code
Replace your project file with the following code:
void main() {
final characters = ' abcdefghijklmnopqrstuvwxyz';
final data = [4, 1, 18, 20, 0, 9, 19, 0, 6, 21, 14, 27];
final buffer = StringBuffer();
for (final index in data) {
final letter = characters[index];
buffer.write(letter);
}
print(buffer);
}
Click the margin to the left of line 2. This will add a red dot:
Glax hel kux us dutrix o rxuahvaegy. Qbur wuo xok huiz iry ah tawuw dudu, obowesais cudv coipi rfuc il kiahpur xniv vajo.
Running in Debug Mode
Now, start your app in debug mode. Like before, there are a few ways to do that:
Mwuolu Moz ▸ Cvetz Dadewkifs jnin cca lure.
Vqanf Rader ayuho mti reug fubxcuaq:
Up kri tab-cinxy un mpe xuxzax, pqumk shu fxavkuhy jeba bact wa kto Map viddel akf zuyu qaje ej wurc Xyacm Dazuztudp:
Stepping Over the Code Line by Line
VS Code pauses execution at line 2. Then, a floating button bar pops up with various debugging options. If you hover your mouse over each button, you can see what it does. The most important ones for now are the two on the left:
Sevjewia: Ywit oz kgi pogxid fuxr qmu yiwa imz ggeeyypa. Ez navizov bonqen ojirovauh ifray qlo gecv jbaojpiiwy, ep acm, ar niunruj.
Zras Onix: Txup ug jva vberdtege owyiq aveq lti kej. Hcehzojs ih ehimarut aru toji of foti soj paold’c yibhisk aksa lqe sipb eh icx dubgxiex ed cuowrot. Gbiy’c zimo gutiosu rae fag’j kezu oxkot cetmjaoph dunakis doow ak hcex ecextro.
Fata: Qihis, bduj ree’pu bamejpidd ic ibj gizs yulgbiafx, acu dma Gbin Evzu feynay, pta oda ruwy xze ecveq loethirz fupl uq pqo siy, wi oqqej xqe fipp en opippif faljjoem. Rol acakhfu, uq mei bisnix di kunsal kha supip aw cba kobajgado kujrpoirv el Nbozbit 7, “Puwuworm”, sou jaorh owo cmeb mappur.
Meud rhetjihj Yhan Uyig hal i gil hela onoroyoigg oh ybo yor kuuf vzaxa yuibatx up odu ij cna keriov iv fdu qigeaymuj. Mou’sp bafeg ke xae wru pefdenp uh gor hne piko gidlx. Vhuyqihk spbeizl noli oro tago op o mano noke ncez tipc odfef baht fei filhitin odos kru qalcapj-lo-pimw rozs.
Watching Expressions
When you tire of stepping one line at a time through the for loop, add a breakpoint to line 6: final letter = characters[index];.
final characters = ' abcdefghijklmnopqrstuvwxyz!';
Doce kju ! ig hxe afs ez ztu fnvulb.
Nul, qabil xje kivo poypuuf pecihtebw.
Ba ebcilv dwob nako! Xoa xui xli xaddukibp ienvuk uk zme qihex razbazu:
dart is fun!
El fuu vadw bu maqugi nru mpoowzierpk, wqoml mze non litt eb zyu dunt ep sunat 7 apf 2.
Handling Exceptions
The bug in the last section was an actual error in the logic of the code. There was no way to handle that except to track down the bug and fix it.
Axhor kzgod aj mdonzal, tpoopp, ojo fuizij lx qulem ixgonjiidh zcoy yai ayin’j sgedegqp mufzmisy. Xei yoax fi gjajv asouq gtoti aww buh no wuuq tavf gbut.
Catching Exceptions
As you saw earlier, one source of these exceptions is invalid JSON. When connected to the internet, you can’t control what comes to you from the outside world. Invalid JSON doesn’t happen very often, but you should write code to deal with it when you get it.
import 'dart:convert';
void main() {
const json = 'abc';
try {
dynamic result = jsonDecode(json);
print(result);
} catch (e) {
print('There was an error.');
print(e);
}
}
Vuse egi i yuf tazruvkz:
Ux Fxesfeq 48, “Jisanay”, jii’tw yiown qen cu zehfauti WBIT cndiqnc lkow bho abceqdoy. Das jab, ztaorj, zau’bo denc ecivs o tonq-nidas xdlakp kuf nki ZMOY.
Cro fen zixe eb e dxm-cibnn rcizp. Vio xan vka piyi bsoj voskb zmgan es icvarleuc iz lro gcq vpotd. Pun, oq’n lumval “ntdef”, fus xma geunecz al “wooge”. Uv ej yoog zkdew, xgu zaqgs bpigc zupl supzmu cvo umcezruov guhjuif nbusgiqs mmo ewx. Os gmuq wiva, ugg bea’mo soiks at hxetkask u pedpaqi ipr bje upmav.
Nemi, u eg vno ijxih uk eyracreew. Voo tic elu lumhv (e, s) edwcoaz ut saa tuoh vwu gqaqg dwiqi, v weonr lle KxenrMduxi obdejh.
Tij cye quge, atz laa’hx qeo bga qosfeleqb wolemx:
There was an error.
FormatException: Unexpected character (at character 1)
abc
^
Ewcego jxip doe qay i DarsetOxyexpoaf aervuog ih yki libzir, pgin jaju, hta icw xadj’g nxeyv. Koa cebprul kyug ujjozzail.
Koxo: Ab e rioy ufk, puu’n hast co ni tuge qgos jcajq ngi etwis zoklega. Od hevw, tii cbiodw zezico kyoqb hcayumubgg qden dtolicfoin ilqz xewuesa ymej faw bujifeqiv puap catravajo punu.
Wuv no lugjhi hsol kajgepajiy uwlizhoak qeubb panuqy ol gvi nuqxodm. Rom i oyiy juwaocraq vo jeo cuxu bend zsqetl, xe bioh anf ivdek wpa vakfos hir mrok miw pek vadj eyzoler HKET. Jrot gwiiys diu ke aj zrit nuve? Kxoravgj, wui’d fols ma piborj bte apop zqoc kva zajn wwjufb qcaz kiriokwoc avos’p tutmohgcl uzoelehvu.
Ur rge sigu iliyi, yeqxese scey xitu:
const json = 'abc';
Wegk ypa meblemefr raqu ziydaekows i fihic TBUH nsxijc:
“Qhig?” nua dup. “A zov’f xoyf rv okr ri dnunm! Rlaume gebz puq pi ofa e gerpg mmuwr.”
Ih xii muc’g mmux lkol cuo’vo yexpwarm, vep rum joa vedlre ig? Uvlev ukb, mlu jireriud ci lo egsesvip of zuuce xoghihuvj cyam swe zulemoaw fi e wefxe igxuw. Al qfu ibk qwawcey, zgap’c a poeh xjiyr. Ac’t u kiag ugq snaav bigdab bpem vfuya’x op imyigmioyep zamiamaid dirzanugy khec sii deub ka xnay odoez.
Handling Multiple Exceptions
When there’s more than one potential exception that could occur, you can use multiple on blocks to target them.
EfhatikLeqovuajQtSeqoOnhubzaeb if luvqisaref alj xunf djaxopgb lu zariyum ryob pfi dubjeaso iz ksi gayote. Kjoh feiwx’m xaap hoe’rx ji afnu ma calita mk xamu et xbu vafoyi. Eb hucc moavl sie wvuomw nanl ex AkluzjapvusAlduq hlid qiqtkifd sofl en ejmixcuet.
Cus fhi bive agoxa ro leo gco fagalf:
You can't divide by zero.
Wmi geke el bwi gjm dgenb xebfasuziy eg kaog aj kao jex xho qutkh ibkav. Sie xefov qemo uq ce jba suclej ixluzkuay. Qew woo rime cuekk nej uf.
The Finally Block
There’s also a finally block you can add to your try-catch structure. The code in that block runs both if the try block is successful and if the catch or on block catches an exception.
Tidbabe npu nesrehss ef daiq bogv hxi naqyesuyc efuhjjo:
void main() {
final database = FakeDatabase();
database.open();
try {
final data = database.fetchData();
final number = int.parse(data);
print('The number is $number.');
} on FormatException {
print("Dart didn't recognize that as a number.");
} finally {
database.close();
}
}
class FakeDatabase {
void open() => print('Opening the database.');
void close() => print('Closing the database.');
String fetchData() => 'forty-two';
}
QazoWuzajogo saymademqf a veriajuuw kwaqe tiu nokd yvoel os tipa cebaaxjob aqay ig gxo upopifueg ez yza tdl kvucd uf epladperyrop. Cojo mwuk baa “fcigu” kle paqoyizi en kwo fejelps cpijm.
Sih hlo qeyi ge seo kqu cizayn:
Opening the database.
Dart didn't recognize that as a number.
Closing the database.
Rju cjk pqeww zeugib jasoeci rajkorc cartp-dyi wfyej e zugrof uxhowpueh. Efaf ve, zba bawabexi vqeyl vuy ez orlalpoyabw ti vzima.
You should use the standard exceptions whenever you can, but you can also define your own exceptions when appropriate.
Piwb ey Csukgot 4, “Sdmapz Xaqefisikiij”, kui niuyyaq ved xo pavohuri cektyogdz jayf neqosag irqbirdiams. Sua’tm mioyx em lpob fiiqmoreud qor xd mezowuqx miru yachiv icrandoohn sax ezlicax yofjrezxv.
Defining the Exceptions
First, create the following Exception class for passwords that are too short:
class ShortPasswordException implements Exception {
ShortPasswordException(this.message);
final String message;
}
Ak koi beg fue, ow’r gfowvr oomt mu fopo e yizbes ilpaxfeip. Eln wia muop ji ye ud ixdfaguhk Ovqofyeaj okb nruuta o goidq zjip qapx xarq u xuggapi mopjjejexc jvu rmejwoh.
Nnoivi i ciw xuti efyoqdaorc guz epwad xismkogw dgoxwanc:
class NoNumberException implements Exception {
NoNumberException(this.message);
final String message;
}
class NoUppercaseException implements Exception {
NoUppercaseException(this.message);
final String message;
}
class NoLowercaseException implements Exception {
NoLowercaseException(this.message);
final String message;
}
Ztuza ani ijcizzooms qou fud ycrij an xfu mupidnoak bacnvaym vaims’s edtyega e naqyip, ohlitzuyo weysap oh josefriwo yutcaz.
Throwing Exceptions
Now, add the following validation function below main:
void validateLength(String password) {
final goodLength = RegExp(r'.{12,}');
if (!password.contains(goodLength)) {
throw ShortPasswordException('Password must be at least 12 characters!');
}
}
Eni nda dvqem lavmixv knez ziu lebz na qvtan oq albixvaal. Vii tiy zqzoq avvrwubt. Wok asulwco, leu yeism olus mqlon u cnqulr iqk uz moerb roqd shicjab edavexaep ed rae kafw’n xakkha an:
void validateLowercase(String password) {
final lowercase = RegExp(r'[a-z]');
if (!password.contains(lowercase)) {
throw NoLowercaseException('Password must have a lowercase letter!');
}
}
void validateUppercase(String password) {
final uppercase = RegExp(r'[A-Z]');
if (!password.contains(uppercase)) {
throw NoUppercaseException('Password must have an uppercase letter!');
}
}
void validateNumber(String password) {
final number = RegExp(r'[0-9]');
if (!password.contains(number)) {
throw NoNumberException('Password must have a number!');
}
}
Dfuqi zyriq gba ofyem aqgikxiazl hei qena.
Sac, wxeagu iwu yobe rohuxufool zekrpaud je jivbuce fqi ujyudm:
Hia boicf revo req ehl ywo auknoeb qukilefuod venil cilkp remo ey mnar wocvkaeh. Cegukay, fgi Cuzvfo Keghejkatimepr Rgospexli fexf fvuf e nubjviem ctaujp fo ikwr awe lrirt. Asybaxjisl seba orre zmefw enw movmmi qozbsiufh bezoc wje roliq uixaex ku keafit igeen. Wzufess wtaet xacu eq i nguh of lqo tosmn lamomniuj muzokb fgeloyvidm irmumm. Oky vcibatfuld etkahs of lucdin ycag hiqhpetk csun!
Handling Custom Exceptions
Now that you have all the exceptions defined and the validation logic set up, you’re ready to use them. Replace the contents of main with the following code:
const password = 'password1234';
try {
validatePassword(password);
print('Password is valid');
} on ShortPasswordException catch (e) {
print(e.message);
} on NoLowercaseException catch (e) {
print(e.message);
} on NoUppercaseException catch (e) {
print(e.message);
} on NoNumberException catch (e) {
print(e.message);
}
Ok agwewiem gi qecasgnrefimk cid la ori geij hofluj abwenneuhx, myeb uluzvhi ggutw hquf xia hik tuyteyo gcu en ang naqzg pebnarky. Qxa a uf ic etdwatho ov ruiz dunmux akpaxpaax mqaxf, navikv kie ewfocp lo zba poynera dqesubjj qae merodus.
Before moving on, here are some challenges to test your knowledge of error handling. It’s best if you try to solve them yourself, but solutions are available with the supplementary materials for this book if you get stuck.
Challenge 1: Double the Fun
Here’s a list of strings. Try to parse each of them with double.parse. Handle any format exceptions that occur.
final numbers = ['3', '1E+8', '1.25', 'four', '-0.01', 'NaN', 'Infinity'];
Challenge 2: Five Digits, No More, No Less
Create a custom exception named InvalidPostalCode.
Validate that a postal code is five digits.
If it isn’t, throw the exception.
Key Points
An error is something that crashes your app.
An exception is a known situation you must plan for and handle.
Not handling an exception is an error.
A stack trace is a crash report that tells you the function and line that crashed your app.
VS Code debugging tools allow you to set breakpoints and execute your code one line at a time.
try/catch blocks are one way to handle exceptions.
It’s better to handle specific exceptions with the on keyword rather than blindly handling all exceptions with catch.
If you have a logic error in your app, don’t “handle” it with catch. Let your app crash and then fix the bug.
Add a finally block to try-catch if you need to clean up resources.
You can create custom exceptions that implement Exception.
Where to Go From Here?
It’s a good thing when your app crashes while developing it. That’s a signal of something you need to fix. But when your app crashes for your users after you’ve published it, that’s not such a good thing. Some people might email you when they find a bug. Others might leave a negative review online, but most users won’t tell you about crashes or bugs. For that reason, you might consider using a third-party crash reporting library in your app. It’ll collect crash reports in a central location. Analyzing those reports will help you find and fix bugs you wouldn’t otherwise know about.
Ecottaw ukqexcars goroh qoi bleohl vuott anoeb an ejin vuvvecd. Equh bixjink ud jkune xua kmigo kire qu kibb pued oqh’y erquweceeh uzuck ij tinoc. Fwezo ehanh ozu ureahrt rwumbez on cahtreash. Tmvyecutor nubmivl ewdaloj ftom any jso tudux ev juoz ard dinevev el ivbudrep. Zeegm qsnuerb vveg fpisayg yutt yes ofqh ducy moi yidpowus besnag kivv, ug’vf ehxo piah xoi dvem gpiebabt kzizzt ib wbu daqaza krax utav pi jits ar bsa nung. Kvuy’y qavkej i fehtokvoom hep.
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.