Case 3 is all about automatic exception chaining.
In the `--throw` case, you're manually passing an Error object to a callback. This requires foresight and discipline on part of the programmer. Every section of code that might conceivable throw an exception needs to be carefully wrapped. E.g. to pick up your very first example again: 

        function bad(file, lineNumber, cb) {
            fs.readFile(file, function(err, data) { 
                // data undefined -> code below throws async error before cb
                var rv = data.toString().split('\n')[lineNumber];
                cb(err, rv);
            }
        };

To make this exception safe, the programmer would need to do:

        function bad(file, lineNumber, cb) {
            fs.readFile(file, function(err, data) {
                try {
                    // data undefined -> code below throws async error
                    var rv = data.toString().split('\n')[lineNumber];
                } catch (e) {
                    cb(e);
                    return;
                }
                cb(err, rv);
            }
        }

Both with fibers or SJS you'd only have to do something like:

       function bad(file, lineNumber) {
           var data = readFileSync(file);
           return data.toString().split('\n')[lineNumber];
       }

Here, any exception thrown because of missing data will automatically propagate; even though it is not explicitly caught and manually chained. IMO this is an important aspect of debuggability - but with `--throw` you're only testing manually chained exceptions. (And with `--athrow` you're currently testing a scenario that I'm pretty sure can _never_ work... which of course is precisely one of the arguments for not using raw callback code :-) )