Error Handling in ActionScript 3: Don’t Make Grenades (or how to not crash Safari)

Preface

At the latest WWDC it was announced that the #1 reason Safari crashes for users is because of Flash, hence the new plug-in sequestering (i.e. if Flash blows up real good, it’ll do so in a way that won’t negatively affect the browser). I agree. If you’ve ever surfed the web using the debug Flash Player, Safari 3 and 4 explode all the time. I don’t know the true cause, but I do know when it’ll happen most often: when you get an error dialogue. These are shown only if you have the debug Flash Player installed, and an error that wasn’t “caught” happens. Sometimes hitting the “Continue” button vs. the “Dismiss All” button will work… but not always… BOOM!  Thank God for History > Reopen All Windows from Last Session.  Here’s how you can help prevent Flash’s bad name from getting worse (that and until Adobe makes it more stable).

Introduction

I’ve written about errors in the past, but wanted to write a more recent, basic, and thorough example since now more than ever, I’m seeing errors all over the web with Flash content nowadays.

Flash Player 9 and 10 have errors.  These are like Java’s unchecked exceptions.  There are 2 types of errors: synchronous and asynchronous meaning “immediately happening while your code is running” and “sometime later when our code is chilling”.  Errors occur when your code does something it’s not allowed, or can’t, do.  In the past, you couldn’t catch these errors nor attempt to recover from them.  Try/catch did exist in a primitive form in AS2/AS1 but didn’t cover all conditions, and sometimes if used would abort entire blocks of code without you knowing where.  Errors are a feature of the new ActionScript virtual machine in Flash Player 9 and 10, and are thus really good.

The best way to prevent errors from getting in your code is a good compiler.  The Flash CS3/CS4, and the Flex SDK’s mxmlc compiler do a very good job of spotting errors before they happen.  The #1 error most of us faced in AS1 was capitalization; if you mispelled a variable, and attempted to access in your code, it obviously wouldn’t work; i.e person.firstName vs. person.firstname; 2 different variables in AS1 (only in the Flash Player 7, 6 was case insensitive). The compiler didn’t see it because there was no strong-typing; anything you typed in a dynamic language is valid because the language is… dynamic.  In ActionScript 2, they mostly fixed this problem, but the #2 problem, null values, were really hard to track down.  This is when your code attempts to access a property of something, say a MovieClip’s x position… but the MovieClip variable is actually null.  In AS2, things just wouldn’t work, and you’d be like, “WTF, mate?“.

Now we have a great complier, and a great runtime that will actually show a dialogue of these errors with where they actually occurred, and why.  The problem is, unhandled errors can cause your program to stop working, and cause the browser (*cough* Safari) to crash.

The Error Dialogue

The error dialogue will show whenever a synchronous or asynchronous error occurs and you don’t catch it (aka handle it).  This code will show a null pointer exception/error:

import flash.display.MovieClip;
var mcMasterKilla:MovieClip;
trace(mcMasterKilla.x);

error-window1

This is because while I defined the MovieClip variable, I didn’t actually create it yet, so I’m attempting to access an x position of a MovieClip that doesn’t exist. BOOM!

The error dialogue (when running in a browser, not the Flash IDE) will pause your Flash movie’s code execution, and wait for you to dismiss the dialogue by clicking Dismiss All or Continue. By default, Continue is what your code does when the SWF is run in the regular Flash Player (non debug). Continue “does its best” to continue running the code after/around the bad stuff. A lot of times the offending code won’t run again. Other times, Flash Player will make a miraculous recovery.

You can create this dialogue as well via a synchronous exception:

throw new Error("BOOM, boom, boom shake the room!");

A throw is a special keyword in ActionScript that you use with the Error class. Flash Player has it’s own set of Error’s with codes, and some classes even extend this class. It must be used with throw, and only Error classes should be printed to the error dialogue in this way.  You can use others, but that’s just crazy talk.

You can also show the error dialogue yourself via an asynchronous exception (in this case, we’re manually doing it as opposed to say, an IOErrorEvent that fires 60 seconds after you make a URLLoader.load call because your interwebs connection went down):

dispatchEvent(new ErrorEvent("splosion", true, false, "Boom, chakka-lakka..."));

When you dispatch events in the Flash Player via dispatchEvent, you don’t get an error dialogue. A special class exists, like Error, for handling asynchronous errors, the ones that occur “later” / “in another frame” / “in another thread” / “separate from your current stack block” / “as an event”. It’s called ErrorEvent (which extends flash.events.Event). If you dispatch an ErrorEvent, or a class that extends ErrorEvent, you’ll trigger the error dialogue.  Both will show the dialogue regardless of where they are executed.

Catching Errors

It is wonderful that Adobe has given us this error facility in Flash Player for both errors and error events. What our compiler doesn’t find, the Flash Player will point out to us at runtime. This is helpful, and makes our code work better, and expedites the time we can get things done correctly.

Sadly, most people do not proactively catch these errors as evident by both the WWDC statement this week (based on my experience of error dialogues always preceding a Safari explosion), and a casual trip around the internets using the debug version of the Flash Player. There are a variety of reasons for this including, but not limited to:

  • not knowing how errors work
  • deadline crunch
  • laziness
  • arrogance, “This condition won’t ever happen, so…”
  • apathy, “If the back-end goes down, we’re screwed anyway, so…”

I can’t fix them all, but I can hopefully fix the first.

You can prevent the error dialogue 2 ways.  To prevent it from showing via synchronous errors (aka throw new Error), you need to catch ’em.  Unlike catching a cold, this is something proactive you need to do.  You use what’s called a “try / catch block”.  It tries to run the code inside the try portion, and if it fails, it’ll run the error portion, passing you the error that occurred. Let’s take the same code above, and wrap the potential explosion with a try catch block:

import flash.display.MovieClip;
var mcMastaKilla:MovieClip;
try
{
trace(mcMastaKilla.x);
}
catch(err:Error)
{
trace("Splosion prevented: " + err.message);
}

Now, we’ve caught it. We’ve prevented the error dialogue from showing, prevented our code from breaking unexpectedly, and taking a proactive opportunity to log the error (in a debug window, a trace, or whatever you use for logging/showing errors).

The thing to note about the catch part is that it will catch ALL errors that occur. If you want to catch all errors, and don’t care about the type of error that happened, you can use the code I just showed you. Sometimes this is the best way because as your code increases in size, you don’t know who “underneath” is throwing errors that will bubble up to your code (yes, Error’s bubble like MouseEvent’s do by default, except they aren’t really events so you have to use a catch).

Here’s an example that catches every possible error that URLLoader.load can throw:

import flash.net.*;
var loader:URLLoader = new URLLoader();
try
{
loader.load(new URLRequest("someurl"));
}
catch(argErr:ArgumentError)
{
trace("Bad headerz");
}
catch(memErr:MemoryError)
{
trace("UTF-8 parsing error... or just not enough RAM for your POST data.");
}
catch(securityErr:SecurityError)
{
trace("Either you're local-networking, or hitting a no-no port.");
}
catch(typeErr:TypeError)
{
trace("t3h URL is t3h null");
}

Insane, right? One connotation that exception handling talks about is “recovering from an error”. If your MovieClip is null, then instantiate it. …however, why not just check for null first? Using try/catch blocks, while a more defensive programming practice, is slower code. So, anytime something may be null, check for null first before accessing it’s properties and methods vs. using a try/catch block.

…but how do you recover from the error’s above? For most errors there isn’t much you can do. What you can ALWAYS do is actually catch most of them, and log them. That way you at least are aware of the problems, and can solve them (if possible) at a later point. Even if you don’t solve them, at least your app doesn’t blow up, nor piss Safari off.

For events, there is no catch all catch. Since Event type’s are magic strings, you have to manually add an event listener for each error event that can occur. Most do not bubble, so just by adding an event listener for it, you are preventing the error dialogue from showing.

Catch All vs. Catch Specific

In Java, there is a keyword that goes next to functions called “throws”. This lets you know what errors it’ll possibly throw if you call it. Thus, you are FORCED to write code that catches those errors. That’s why some Java code can have a lot of try/catches everywhere. The pro, however, is that you know what you’re dealing with, and the compiler helps you.

We don’t have this in ActionScript 3. So, while you can refer to the documentation to see errors URLLoader.load will throw and other boilerplate classes, there is no mechanism for custom classes for errors. For ErrorEvents, you can utilize the [Event] metadata tag, but those are optional for code hinting. You can put those tags on an Interface to help document intent, but the compiler doesn’t force you to write a dispatchEvent with that error event class.

When dealing with code, whether you know the code or not (yours vs. a 3rd party API), you should use try/catch on those methods you know can throw errors. If you don’t, and later find methods do actually throw errors (maybe it came with no docs or original developer(s) didn’t think it’d throw an error), wrap it in a try/catch. A default error in the catch is fine.

For events, ensure at the very least you’ve added event listeners for all the error events. Just…

Swallowing Errors

…don’t swallow the errors. Swallowing errors refers to having a catch block that, like zee goggles, does nothing. The same goes for event listeners for error events that are empty functions. This means that your program has an error occur, but no one ever knows about it. Unlike the tree falling in the woods, YES the error actually occurred even though no one heard it.

This is a bad thing to do for 2 reasons. First, things could be blowing up in your application, and you don’t know about it. Like if NORAD suddenly evaporated, yet more death involved. That’s like going back to AS1. If you don’t know about an error, you cannot fix it, nor attempt to recover from it if it cannot be fixed.

Here’s 2 examples:

import flash.net.*;
var loader:URLLoader = new URLLoader();
loader.addEventListener(IOErrorEvent.IO_ERROR, onError);
try
{
loader.load(new URLRequest("someurl"));
}
catch(err:Error)
{
// I am...
}
function onError(event:IOErrorEvent)
{
// ... a slack bastard
        // TODO: get motivation to fix this
}

Recovering From Errors

Secondly, not recovering from errors usually leaves the user confused on what the heck just happened. The app appears to be not working. You should view catch blocks as your opportunity to provide the user with a meaningful dialogue on what happened, and/or what they can do to continue. To say it another way, you can offload the error handling to those whose job it truly is: The Designers. Whether IA/UX/Visual Designer… doesn’t matter. If something breaks, what do I do? A lot of time it’s easy. Those crayon pushers will get a sarcastic smirk on their face when asked, “What if their internet has gone down and we try to save their work to the server?” “Dude, tell them to re-connect!”.

Seriously, a lot of things can go wrong in software, and this is an opportunity for you to provide a gracious error handling strategy in your app, even if it’s just showing an Alert dialogue with, “Set Sail for Fail”… that’s a cop-out though. Again, do your best to think about why the error could occur, and what you would expect to be able to do as a user. A lot of times you may feel like you’ll reach the inevitable conclusion, “they’re screwed”. If you do, think harder. Ask the designer. You’re using a runtime capable of providing rich feedback to the user; make use of it.

Exception to the Exceptions

The exception to the above rules is NetStream.close(). I’m not sure why it throws an exception, but I don’t really care if it doesn’t close. This is the one time where I always have an empty catch block; nothing negative happens if a NetStream doesn’t close, nor is there anything you can do. I usually create new instances of NetStreams anyway.

Error Handling Process

There are 3 types of errors in a project. The ones you know about, the ones you don’t, and null pointers. The ones you know about are easy; they are in the ActionScript documentation. Just add try/catch blocks around those methods or addEventListeners for the error events. The ones you don’t know are from your own code throwing errors during development. This is ok as well because you’ll find them as you develop, and even with a little QA.

The null pointers, however, are a separate breed. Yes, you don’t know about them because if you did, you wouldn’t have them. However, null pointers are notorious for sneaking by compilers. Additionally, real-world data (hitting a production ready web service vs. the one you’ve been using for development, local XML vs. real, user entered data vs. developer entered data, etc.) has a knack for going into a system in a way the original developer didn’t expect. That, and when real users start using it, you start having more people test more areas. This greater area of coverage has a high probability of finding areas you and your team couldn’t find on their own based on just sheer man hours of using the app.

So, the errors you know and don’t know are fine; that’s the point of this article. Catch ’em, and log ’em at a bare minimum. For the null pointers, even with massive amounts of if (someVar) won’t suffice. Just do the best you can and know post launch most of the errors you’ll get (assuming you follow my next advice) will be null pointers.

Cure the Disease, Don’t Treat the Symptoms

In my experience, the #1 cause of errors in AS3 based projects is bad data. Garbage in, garbage out. If you have data going into your code from an outside source, this is the weakest link in the chain, and is also the most often cause of problems. If you are parsing XML into ValueObjects, and building View’s around those ValueObjects, and your View looks funny, often times it’s the parsing code. You may think it’s a problem with your GUI code, or perhaps the Controller (code used to have Model/data passed to View/GUI controls) fubarred it during transfer. Often, however, it’s the bloody Factories; classes or just functions responsible for parsing the data.

One way to prevent having to write a lot of try/catch blocks, if null tests, and adding event listeners for error events is to ensure your service layer is tight. This means writing unit tests on all the data that gets into your system. If you’re building a photo slideshow from external XML, write code to ensure once parsed, the Array’s of images you actually created are full of yummy Strings vs. null values. Nothing should leave a Factory class that hasn’t been validated via quality control; in this case either if null for properties at a minimum or unit tests at the ideal level.

Good data in your system means most of your errors are known errors. The more proactive you are here, the less reactive you’ll need to be later on.

Finally

Finally is another keyword you can put after the catch. It will run regardless of the try or catch running. It’s typically used for clean up. I never use it because your code execution in a catch once complete will continue running the rest of the original function it’s in. Additionally, I sometimes put return statements in my catches when I know I’m royally screwed, ensuring the finally will never run.

Don’t Create Explosions: Anti-Custom Errors

When first researching error handling in the Java world to see how they handled it, I came upon an article that explained how you SHOULD do it. Java has been around for a long time, and they’ve already solved a lot of problems we as ActionScript developers had. So I knew I’d probably find the answer if I did a lot of digging, and I was right.

The article talked about how try/catch/finally blocks make Java code very unreadable and un-encapsulated from an OOP perspective. The first is opinion (which I agree with) and the second is fact. While Java’s throws keyword does help you via the compiler recognizing it and ensuring your code handles it… why are they doing this? The third is, if an API has a bunch of things that it’s attempting to handle internally, and something breaks, why is it bubbling up those problems to you as the API consumer? While it’s really cool to know during development why at URLLoader.load fails so I can attempt to fix it, during production it’s useless. Either it worked or didn’t; just tell me that, with details I can find if I’m so inclined.

Take the URLLoader.load example from above. The ONLY error you can reasonably recover from is the 2nd SecurityError where you’re hitting a port that’s reserved or not open. That’s it? The rest of the situations you’re just f’ed? If this were Java, that wouldn’t be helpful at all. And that is the point the author makes. Most errors are un-recoverable. The best you can do is show a user friendly dialogue, and “do the best you can”, whether polling till the Internet is available again, or asking the user to hit a server later if your middle-tier went down (aka Twitter’s Fail Whale).

Since you’re effectively screwed, making life worse for the developer by forcing them to write more code to ensure they in fact know they are potentially screwed, yet cannot do much about it is a waste of time. The author offers an alternative.

His suggestion is to condense errors into 1 generic one with details that those who care about can access if they want to. Like doing 1 try/catch on URLLoader.load vs. the 4 I showed above. Whether you get a SecurityError or an MemoryError… there isn’t anything you can do to recover in that situation. So, if you’re writing a class, and there are a bunch of things that could go wrong, throw a generic Error instead with a public property on it that has what went wrong such as “lastError”. In ActionScript, you can just use the Error class since it already has this for you. Since most errors are just logged, this makes it really easy to handle. No matter what goes wrong, your code is concise.

However, in ActionScript 3 I offer 2 different suggestions that I actually practice.

The first is don’t create explosions. Don’t use the throw keyword; don’t throw errors. There is no strongly typed way in ActionScript 3 currently to “know” if a class throws an error. You break OOP by using the throw keyword. Additionally, you leave surprises for the other developer (maybe even you) when using the code since there is no way for them to know it’ll do that unless they are intimate with it.

The second is to create opt-in errors. Throws in Java are opt-out; meaning you have to write a try/catch for your code to actually compile, even if you have no intention of doing anything with the error (NetStream.close, don’t have comps from the designer yet, don’t know why an error is occuring yet, etc…). Throws in ActionScript are opt-out in a worse way; at first they aren’t handled because you don’t know about them, and once you do, you may not like having to catch it in a variety of places.

You create opt-in errors by creating a class that extends Event, and has a public property called “lastError”. When an error occurs, you create this event, set the lastError to whatever the message was on the Error, or text on an ErrorEvent, and dispatch it. Since it doesn’t extend ErrorEvent, it won’t show the error dialogue. This has the following pro’s:

  1. You can strongly-type the event being dispatched via the [Event] metadata tag.
  2. Makes your code not unexpectedly explode.
  3. Gives the developer the option to listen to an error; not forced to write more code.
  4. The error handling code can be written the same way whether it’s a synchronous or asynchronous error.
  5. You write your error handling code once vs. many times using try/catch around each potential method/property and multiple error events.

To create an opt-in error is to create an error that can occur, but won’t blow up your app if it occurs.  The class that has the issue captures the error, logs it internally, but doesn’t allow the error to show the error dialogue. If you give the class to another developer, you are ensuring you aren’t handing her/him a potential code grenade waiting to explode unknowingly.

For existing systems, or when creating API’s, you can feel comfortable you’re not part of the problem.  Your code won’t explode, and when the developers are ready to handle the errors (if ever), you have provided a simple mechnism for them: 1 event called “error”.

Additionally, you are giving her/him the option of handling the error.  This is very important for Flash Developers who are typically put on very tight deadlines.  A lot of times they’re not hitting a lot of error prone back-ends, their designers haven’t given a 2nd thought to errors, and/or there is already an existing culture of getting it working “good enough” to get it out of the door since agencies are deadline driven.  This may seem trivial, but it’s not.  To reiterate, in those environments, OOP is a nice to have, but if it threatens the deadline, it’s not used.  You cannot risk your Flash’s small part in a larger ad campaign because of your guilt for not following OOP Purism.

This makes error handling in the code more consistent.  Instead of try/catches in some places, and addEventListener’s in others; it’s all event driven.  Obviously in the lower-level classes, you’ll have to write try/catch blocks to create custom error events, but hopefully that’s abstracted away for others, and you, to not have to worry about. An event listener is only written once, whereas try/catch around every method can get tedious and violates DRY (don’t repeat yourself) principles.

Here’s an example:

import flash.net.*;
var loader:URLLoader = new URLLoader();
loader.addEventListener(IOErrorEvent.IO_ERROR, onError);
try
{
loader.load(new URLRequest("someurl"));
}
catch(err:Error)
{
dispatchError(err.message);
}

function onError(event:IOErrorEvent)
{
dispatchError(event.text);
}

function dispatchError(errorString:String)
{
        var event:ServiceEvent = new ServiceEvent(ServiceEvent.ERROR);
        event.lastError = errorString;
dispatchEvent(event);
}

Another Example Opt-in

An example of this technique is the HTTPService that comes with the Flex SDK.  It has an API for doing rest based services, aka anything related to getting dynamic data that is NOT a WebService, SOAP, or Remoting.  If it’s not those 3, you use HTTPService.  Loading JSON, XML, REST based services (aka URLVariables), text… it’s all there.  If you’ve ever cracked him open, he’s insanely complex for a class that abstracts URLLoader (there are others, but you get the point).  He only exposes 3 events, 2 of which are the only ones used by most developers: result and fault.  Result for the most part is if your stuff worked.  You may not like the data, but at least you got it (similiar to URLLoader’s Event.COMPLETE).

Fault, while being 1 event, has a large sub-system of error reporting.  So while you only write 1 event handler for fault, the number of errors is very large.  This makes the code easy to write, and easy to debug.  If you don’t add an event listener for fault, it doesn’t blow up in your app.

Conclusions

As you can see, errors are helpful in Flash Player to help you debug your code, but also require more work to handle correctly.  In addition, Safari appears to be made unstable when errors get through (sometimes Firefox), so you have incentive to at least catch them at the very least.  You should at the very least trace the error out vs. swallowing it.  When creating your own errors, make sure you dispatch an event that extends Event instead of ErrorEvent so you don’t force explosions on those (including yourself) using that code.  If the code you write has the potential for a lot of things to go wrong, make 1 error with a property for finding out more specific information about the error to keep your class encapsulated, yet easy to work with.

There is no global exception handling, unfortunately, so it’s hard to get all the asynchronous ones.  Additionally, it’s impossible to catch the “load never completed” error… the one that fires while the SWF is actually loading into the Flash Player itself.  Coincidentally this error is also the one that almost always crashes me Safari.  I always cringe in fear when closing tabs that has a Flash video player.

In the future, hopefully 3 things will happen.  First, Adobe will make it more stable (even though apparently Apple already has, haven’t tested Safari 4 enough yet… it’s still blowing up for me all the time).  Second, we can catch the un-catchable.  Third, there will be some mechnism for global exception handling so we can ship SWF’s with assurance it won’t blow up without us knowing.

Don’t write grenade code, write opt-in errors.

11 Replies to “Error Handling in ActionScript 3: Don’t Make Grenades (or how to not crash Safari)”

  1. Excellent post. Thanks so much — read through it all, but will come back to it again.

    Love your writing style as well :-) If you’re running out of Fresh Prince of Bell Air quotes, maybe you can use (the) Prince next time: Housequake (“What was that? After shock!”) or Tick, Tick, Bang (“Bang, b-b-bang, bang”).

    Anyway, great read.

    Erik

  2. Firstly, I have to admit that I skim-read that.

    The sad fact of life is that software bugs are not a disease that can be cured. Anyone arrogant enough to claim their code is bug-free is setting themselves up for a fall.

    So my question is, does anything in this article address this issue?
    https://bugs.adobe.com/jira/browse/FP-444

    Cheers,
    Brindy

  3. Great article. I too am plagued with with Safari crashes (most commonly due to the closing a tab with a flash video player as you explained). I’ve downloaded Safari 4 while I read this article so fingers crossed it performs more gracefully.

  4. Hi Jesse.

    An excellent write up. This is definitely one area that has received little love from the actionscript community.

    Some “error” conditions are expected, such as not finding a value on a list or in a hash. In those cases a return code that signals that error is appropriate.

    But somethings are unpredictable, since they depend on other systems (http requests, writing to disk). Basically any IO is outside of your control. For those cases an exception makes sense, it’s not something that you control (you could’ve anticipated it, though).

    It’s also a pity that the native api / event is so awkward, no way to catch all and other oddities. We’d be much better off if all loading operations would dispatch a general error containing more details to be inspected latter on, for example.

    As a sidenote, the netstream.close was the only case where the native api would throw an exception in AS2, as far as I can remember.

    Cheers

  5. Thanks for a great article Jesse. I have been dabbling in ActionScript for a couple of years now and I will freely admit that handling errors did not enter my coding practice at all. This was in part due to me just learning the nuts and bolts first but mainly because I didn’t think I would ever have to handle errors anyway since my coding was just for fun. Just recently though I have begun writing code for real-life situations and suddenly the need for error handling has jumped out and bit me hard an my ass! The shame and embarrassment of it when you demo an app and Flash Player immediately spits out an error dialogue! Anyway my point is that you writing this article has come at the exact time I was looking into the whole error handling thing. Much more understandable than the official documentation for me.

    Thanks man!

  6. A suggestion while developing may be to use ErrorEvent as your primary Event, but use conditional compilation to swap this out for the Event class when releasing the production version.

Comments are closed.