Throw badarg with more information from a NIF?

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.

1 Like

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” }.

1 Like

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?

1 Like

Technically I could also return {error, Reason} instead of throwing badarg :slight_smile: 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