I’ve just stumbled on Eep 0054 - Erlang/OTP that’s about producing more useful badarg
errors. Is there a way to produce such badarg
errors from NIFs? enif_make_badarg
does not accept any extra parameters, nor does enif_raise_exception
.
Apparently, currently, it’s not possible:
https://groups.google.com/g/erlang-programming/c/5P4ZqRzjXnc
There are no NIF primitives yet to raise that type of exception, but we have been talking about adding them. The best you can do now is to throw an error and catch it in a NIF wrapper and then rethrow it again with the extra error_info. Something like:
my_wrapper(Arg1) →
try my_nif(Arg1)
catch error:badarg →
error(badarg, [Arg1], [{error_info, #{}}])
end.
format_error(_Reason, [{?MODULE, my_wrapper, 1, }|]) →
#{ 1 => “invalid password” }.
enif_raise_exception(ErlNifEnv* env, ERL_NIF_TERM reason)
's second argument can be any term.
The socket NIF consistently uses {invalid, What}
. This becomes an exception of class error
with content {invalid, What}
.
Might this be useful in your case?
Technically I could also return {error, Reason}
instead of throwing badarg My code uses similar code like this (from the examples) to check the arguments
if (!enif_get_int(env, argv[0], &x)) {
return enif_make_badarg(env);
}
I was wondering maybe there’s a way to modify this pattern to produce more descriptive error messages in the shell.
The easiest way is to add a “proxy” function in the Erlang module, that throws exception based on the NIF result. I used this technique in sqlite
bindings, e.g. this way: sqlite/src/sqlite.erl at master · max-au/sqlite · GitHub