Search code examples
c++node.jsnode.js-addon

Node API throws it's own error message instead of own error message


I am trying to write the following function for NAPI.

int addon::fakeAdd(int a, int b)
{
    return a + b;
}
Napi::Number addon::addWrapped(const Napi::CallbackInfo &info)
{

    Napi::Env env = info.Env();
    if (info.Length() < 2 || !info[0].IsNumber() || !info[1].IsNumber())
    {

        auto x = Napi::TypeError::New(env, "You did not provide 2 numbers");
        x.ThrowAsJavaScriptException();
    }

    Napi::Number num1 = info[0].As<Napi::Number>();
    Napi::Number num2 = info[1].As<Napi::Number>();
    int returnValue = addon::fakeAdd(num1.Int32Value(), num2.Int32Value());
    return Number::New(env, returnValue);
}

I am exporting this function as add. When I call it from javascript using to arguments (e.g. addon.add(1,2)) everything works like a charm and I get the correct result which is 3.Now I want to handle the cases that user did not provide any arguments to my functions or (one or both) arguments are not a number.In that case I want to throw a custom message("You didn't provide 2 numbers").However when I try to call my method from JavaScript without any arguments I get the following error:

console.log(addon.add());
                  ^

Error: A number was expected

Is there a reason I get this specific message instead of the one I wrote inside the if block?

Here is how I export my functions:

Napi::Object addon::Init(Napi::Env env, Napi::Object exports)
{
    exports.Set("add", Napi::Function::New(env, addon::addWrapped));
    exports.Set("getOsName", Napi::Function::New(env, addon::getOSNameWrapped));
    exports.Set("writeToFile", Napi::Function::New(env, addon::writeFileWrapped));
    return exports;
}

Here is binding.gyp file

{
    "targets": [{
        "target_name": "testaddon",
        "cflags!": [ "-fno-exceptions"],
        "cflags_cc!": [ "-fno-exceptions" ],
        "cflags_cc":["-std=c++1z" ],
        "sources": [
            "cppsrc/main.cpp",
            "cppsrc/functionexample.cpp"
        ],
        'include_dirs': [
            "<!@(node -p \"require('node-addon-api').include\")"
        ],
        'libraries': [],
        'dependencies': [
            "<!(node -p \"require('node-addon-api').gyp\")"
        ],
        'defines': [ 'NAPI_DISABLE_CPP_EXCEPTIONS' ]
    }]
}

Solution

  • Assuming that you have C++ exceptions disabled in binding.gyp (cflags/cflags_cc="-fno-exceptions", defines:"NAPI_DISABLE_CPP_EXCEPTIONS") you should read this section of the error handling documentation :

    After throwing a JavaScript exception, the code should generally return immediately from the native callback, after performing any necessary cleanup.

    An their example:

    Napi::Error::New(env, "Example exception").ThrowAsJavaScriptException();
    return;
    

    Calling ThrowAsJavaScriptException() will not throw a C++ exception and therefore your C++ function will continue to run if you don't return.