Erlang uncatchable exception - exception

I have the following code in Erlang, in which I'm mecking an nonexistent module.
In some versions of Erlang/meck this generates an exception that seems uncatchable.
Anyone knows if there is an "uncatchable exception" feature in Erlang ?
try
meck:new(i_dont_exist),
io:format("No exception in this version of Erlang ... :( "),
no_problems
catch
exit:_ -> exit;
error:_ -> error;
throw:_ -> throw;
_:_ -> what_class_is_it
after
io.format("in the after~n")
end.
When I execute this code this is what I get (notice that not even the "after" clause is being executed so it looks more like a bug to me):
** exception exit: {undefined_module,i_dont_exist}
in function meck_proc:resolve_can_expect/3 (src/meck_proc.erl, line 402)
in call from meck_proc:init/1 (src/meck_proc.erl, line 194)
in call from gen_server:init_it/6 (gen_server.erl, line 304)
in call from proc_lib:init_p_do_apply/3 (proc_lib.erl, line 227)
I have also tried with the "catch" expression with the same result:
> catch meck:new(i_dont_exist).
** exception exit: {undefined_module,i_dont_exist}
in function meck_proc:resolve_can_expect/3 (src/meck_proc.erl, line 402)
in call from meck_proc:init/1 (src/meck_proc.erl, line 194)
in call from gen_server:init_it/6 (gen_server.erl, line 304)
in call from proc_lib:init_p_do_apply/3 (proc_lib.erl, line 227)

What's happening here is that meck:new spawns a new process (a gen_server process using the meck_proc callback module), and that process exits with the undefined_module error. (You can get it not to do that by passing the non_strict option to meck:new.) This new process is linked to the calling process, which means that an exit signal will be sent to the calling process, and the calling process will exit as well, without being able to catch the signal.
You can avoid that by making your calling process trap exits:
process_flag(trap_exit, true)
which will turn the exit signal into a message that you can receive; see the manual for more details. However, as a general rule you should avoid trapping exits, as it makes error handling more complicated (as opposed to the default "crash, restart").

Related

catching classes that do not inherit from BaseException is not allowed

I'm making a custom plugin to query a database for user info to aide customer support. My backend is slack.
Everytime I start the bot command I'm greeted with:
Computer says nooo. See logs for details:
catching classes that do not inherit from BaseException is not allowed
I'm not sure if this is warning me that I'm attempting to catch an exception that isn't a BaseClass in my code or if an unknown exception was raised and caught elsewhere outside of my plugin.
To debug I tried:
try:
do_the_thing()
except (TypeError, ValueError) as e:
return('Something went wrong.')
I also tried:
try:
do_the_thing()
except Exception as e:
return('Something went wrong.')
And I still get the errbot admonition. Note that the command still runs and does the right thing where there is no exception raised by do_the_thing().
It means that:
Somewhere in your code you have an except ... statement where the exception ... (or one of the exceptions in the sequence ...) is not a subclass of BaseException, and
An exception is being thrown that is caught by that except ... statement.
The TypeError can be raised only when an exception is actually thrown because the names you give to except ... must be evaluated for their current values at that time; just because TypeError referenced a particular class at one point in the program's execution doesn't mean it won't be changed later to reference another object (though that would be admittedly perverse).
The Python interpreter should be giving you a full traceback of the exception; the first thing you need to do is find this. It could be occurring in one of two situations. (This is for single-threaded programs; I'm assuming your program is not multithreaded.)
During the execution of your program, in which case the program will be terminated by the exception, or
During finalization of objects (in their __del__(self) functions) in which case the error will be printed to stderr.
In both cases there should be a stack trace, not just the error message; I've confirmed that at least on Python ≥3.4 a stack trace is printed out for case 2.
You then need to follow this stack trace to see where the problem lies. Remember that the names you give to except ... are variables (even things like TypeError) that can be reassigned, so that you could conceivably be dealing with a (perverse) situation like:
TypeError = False
try:
...
except TypeError:
...
But more likely it will be something obvious such as:
class MyException: # Doesn't inherit from Exception
...
try:
...
except MyException:
...
There is one special case you need to be aware of: if you are seeing messages to stderr (case "2. During finalization," above) printed out as your program exits that means that the exception was thrown during cleanup as the interpreter shuts down, where random variables throughout the program may have already been set to None as part of the cleanup process. But in this case your program should still exit successfully.

AllegroServe Exception Handling

How can I avoid getting an error when passing as argument to the function do-http-request an invalid host.
Is there any way that I can catch the error like the Java's exception-handling mechanism ?
Sure, CL has a very nice condition system. One easy option would be wrapping the call to do-http-request in ignore-errors, which returns nil (and the condition as a second value) if an error condition was signalled in the wrapped code. You could then check for nil afterwards.
If you want something more like exception handling in Java, just use handler-case and add an appropriate error clause (I don't have AllegroServe installed, but I suppose you get a socket-error for providing a wrong URL – just change that part if I misread):
(handler-case
(do-http-request …)
(socket-error ()
…))
If you need finally-like functionality, use unwind-protect:
(unwind-protect
(handler-case
(do-http-request …)
(socket-error (condition) ; bind the signalled condition
…) ; code to run when a socket-error was signalled
(:no-error (value) ; bind the returned value
…)) ; code to run when no condition was signalled
…) ; cleanup code (finally)
You can even get more fancy, and e.g. use handler-bind to handle the condition stack upwards by invoking a restart somewhere down the stack, without unwinding it. For example, if do-http-request provided a restart to try again with another URL, you could handle your error condition by invoking that restart with a new URL to retry. I just mention this for the sake of completeness – it would be overkill for your use case, but being able to resume (possibly expensive) computations easily can be a rather convenient feature.

Catch "Tcl Interpreter Error"

Is there any way to catch the global "Tcl Interpreter Error"? For example I would like to automatically store in some file the message that follows.
The core command for trapping any kind of error thrown by Tcl is catch. It takes at least one argument, a script to evaluate, and returns the result code from evaluating that script. The result code is 1 when an error occurs, 0 when there was no error, and a bunch of other things in other cases (indicating other types of usually-non-error exception). The catch also takes an optional argument that names a variable into which to write the result of evaluating the script or the error message. The global variable errorInfo will contain the stack trace in the case of an error (or from 8.5 onwards you can get the interpreter state dictionary with a further variable name passed to catch).
To trap an error in some script “foo.tcl”, you would use code like this:
if {[catch {source foo.tcl} msg]} {
puts "I got an error: $msg"
puts "The stack trace was this:\n$errorInfo"
}
It's up to you to work out how to write that out to a file if you want. (I use this technique with an outer script that implements a carefully tested error trap and which loads an inner script that does the real work. I find it works well. Or you can call procedures in that “caught” script. Up to you really; Tcl should make all errors trappable, and there are very few conditions which slip through.)
The other route that errors can be reported is via bgerror, which is called to handle errors that occur during event processing. It's a procedure you can write your own version of; it will be given a single argument when called that is the error message, and will have the global errorInfo set correctly when called:
proc bgerror {msg} {
global errorInfo
puts "I got an error in an event: $msg"
puts "The stack trace was this:\n$errorInfo"
}
If there is no implementation of bgerror defined, the stack trace is just written to the stderr channel. If you're using the Tk package, an implementation of bgerror is provided which pops up a dialog box describing the problem.
Try the bgerror or interp bgerror commands.
Read the bgerror documentation, it has a simple example.

BeepBeep and ErlyDB integration issue

Further to my adventures with Erlang and ErlyDB. I am attempting to get ErlyDB working with BeepBeep
My ErlyDB setup works correctly when run outside of the BeepBeep environment (see Debugging ErlyDB and MySQL). I have basically take the working code and attempted to get it running inside BeepBeep.
I have the following code in my controller:
handle_request("index",[]) ->
erlydb:start(mysql,Database),
erlydb:code_gen(["thing.erl"],mysql),
NewThing = thing:new_with([{name, "name"},{value, "value"}]),
thing:save(NewThing),
{render,"home/index.html",[{data,"Hello World!"}]};
When I call the URL, the response outputs "Server Error".
There is no other error or exception information reported.
I have tried wrapping the call in try/catch to see if there is an underlying error - there is definitely an exception at the call to thing:new_with(), but no further information is available.
The stacktrace reports:
{thing,new,[["name","value"]]}
{home_controller,create,1}
{home_controller,handle_request,3}
{beepbeep,process_request,4}
{test_web,loop,1}
{mochiweb_http,headers,4}
{proc_lib,init_p_do_apply,3}
Use pattern matching to assert that things work up to the call to thing:new/1:
ok = erlydb:start(mysql,Database),
ok = erlydb:code_gen(["thing.erl"],mysql),
You include only the stack trace, look at the exception message as well. I suspect that the error is that you get an 'undef' exception. But check that it is so. The first line in the stack trace indicates that it is a problem with calling thing:new/1 with ["name", "value"] as argument.
It is slightly odd that you show one clause of handle_request that is not calling home_controller:create/1 as per {home_controller,create,1} in the stack-trace. What do the other clauses in your handle_request/2 function look like?

How to catch Exception Message in Erlang?

This is the Exception message thrown by Gen_server when its not started.
(ankit#127.0.0.1)32> R11 = system_warning:self_test("SysWarn").
** exception exit: {noproc,
{gen_server,call,
[system_warning_sup,
{start_child,
{system_warning_SysWarn,
{system_warning,start_link,[{system_warning_SysWarn}]},
permanent,10,worker,
[system_warning]}},
infinity]}}
in function gen_server:call/3
in call from system_warning_sup:'-start_child/1-lc$^0/1-0-'/1
in call from system_warning:self_test/1
(ankit#127.0.0.1)33> R11.
* 1: variable 'R11' is unbound
Now, What I want to do is to catch this exception message & put into variable R11 (showed above as unbound). I want to do so because if gen_sever is not started then I want to start after getting this message. I also tried using handle_info but not able to trap the exception or may be not able to implement it correctly. Can any body please help me with this problem providing some code for example.
Both the answers from #W55tKQbuRu28Q4xv and #Zed are correct but a little terse. :-)
There are two ways to locally catch an error: catchand try. Both will also catch non-local returns generated by throw.
catch is the older and simpler of the two and has the syntax catch Expr. If an error occurs in the expression being evaluated then catch returns {'EXIT',ErrorValue}, otherwise it just returns the value of the expression. One problem with it is that there is no way to see how the error return value has been generated so it can easily be faked in the expression. In the same way you can't see if the return value comes from a throw. N.B. this is not a bug but a feature. Also it is a prefix operator with a low priority so you would normally use it like:
R11 = (catch system_warning:self_test (....))
to avoid confusion. This was a mistake, it should have been catch ... end.
throw is more complex and allows you much greater control over over what to catch and how to handle both the normal returns and error/non-local returns. See the manual for a full description. #Zed's example shows the simplest case which catches everything.
> try
> R11 = system_warning:self_test("SysWarn")
> catch
> Ex:Type -> {Ex,Type,erlang:get_stacktrace()}
> end.
Try to use 'catch':
R11 = catch system_warning:self_test (....)