The Unstoppable Exception

Brujo Benavides
May 18, 2016 · 5 min read

Debugging >> Fixing

How many times have you said or listened the following sentence?

It took me one whole day to debug the issue, but then I fixed it in literally 10 seconds with just one line of code.

In my ~15 years of development work, I’ve said that countless times. And I found out that it’s something that almost all developers can relate to. The harder it is to debug an issue, the simplest the solution it requires.


Chris Prine / Denzel Washington — Unstoppable (2010)

The Issue Itself

In most Erlang/OTP applications, if you’re going to have gen_servers running, you usually start them as supervisor children. But, some times, you actually need to start those gen_servers by hand and deal with the result of gen_server:start_link(…).

The Docs

That’s when you go to the Erlang docs and read the following about the relationship between start_link/3,4 and init/1:


The Dumbest Server

To showcase my problem, let me show you the dumbest possible way to duplicate a number in Erlang while also showing you the simplest possible version of a gen_server implementation:

1> c(dumb_math).
{ok,dumb_math}
2> dumb_math:dup(1).
2

The Unexpected Exception

So far, so good. Now, according to the doc we read before, if init/1 function fails, gen_server:start_link/3 should return {error, Reason} and therefore we can expect line #5 in our code to produce a badmatch exception. But instead of that, look what happens…

3> dumb_math:dup(bad).
** exception exit: badarith
in function dumb_math:init/1 (dumb_math.erl, line 8)
in call from gen_server:init_it/6 (gen_server.erl, line 328)
in call from proc_lib:init_p_do_apply/3 (proc_lib.erl, line 240)
1> c(dumb_math).
{ok,dumb_math}
2> dumb_math:dup(1).
2
3> dumb_math:dup(bad).
** exception exit: notnum
4>

Catch me if you can!!

In any case, we know how to deal with exceptions, don’t we? Let’s see…

3> dumb_math:dup(bad).
** exception exit: notnum
4> catch dumb_math:dup(bad).
** exception exit: notnum
5> try dumb_math:dup(bad) catch Type:Error -> {Type, Error} end.
** exception exit: notnum

What’s going on here?

I’ve got to admit that, for experienced Erlang devs, this example in particular makes things much easier to understand than the ones I stumbled upon in The Real World™. In those cases, most of the time the call to gen_server:start_link/3,4 was hidden inside a function that was called by another which in turn was called by yet another one and so on… with the outermost one including a try…catch.




6> process_flag(trap_exit, true).
false
7> dumb_math:dup(bad).
notnum

Erlang Battleground

Strange and funny battle stories found while programming in the Erlang Ecosystem

Brujo Benavides

Written by

Father / Long Distance Walker / Erlanger @ AdRoll via BairesDev / Trainer @ CodeMentor - You can… https://www.buymeacoffee.com/elbrujohalcon

Erlang Battleground

Strange and funny battle stories found while programming in the Erlang Ecosystem