node-addon-api: how can i throw errors that show the trace from javascript

hello,

i want to throw via node-addon-api, but the problem is that when i catch nodejs is not receiving the trace. for example:

(async() => {

    try {

        const thermo = require('../../build/Release/thermo')
        const pi = await thermo.piWorker(10000000)
        console.log('await', pi)

    } catch(e) {
        console.error('node-addon-api error')
        console.error(e);
    }

    console.log('')

    try {
        throw new Error('nodejs error')
    } catch(e) {
        console.error('nodejs error')
        console.error(e)
    }

})()

image

In C++. I am using the usual: Napi::AsyncWorker::SetError("test error"); function.

So when I use await in the async method, it is not showing trace, so i will be hard to debug.

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Comments: 15 (7 by maintainers)

Most upvoted comments

well, i use promises, the problem is, I cannot give an error, only a napi_value, which cannot be an error:

    void OnOK() {
        deferred.Resolve(Napi::Number::New(Env(), estimate));
    }

    void OnError(Napi::Error const &error) {
        deferred.Reject(error.Value());
    }

if i try to reject a promise with a Napi::Error, i get an error:

    void OnOK() {
        deferred.Resolve(Napi::Number::New(Env(), estimate));
    }

    void OnError(Napi::Error const &error) {
        deferred.Reject(error);
    }

the error:

/home/patrikx3/Projects/sygnus/thermo-range-workspace/thermo-range-ngivr/native/pi-worker.cc: In member function ‘virtual void PiWorker::OnError(const Napi::Error&)’:
/home/patrikx3/Projects/sygnus/thermo-range-workspace/thermo-range-ngivr/native/pi-worker.cc:42:30: error: no matching function for call to ‘Napi::Promise::Deferred::Reject(const Napi::Error&)’
         deferred.Reject(error);
                              ^
In file included from /home/patrikx3/Projects/sygnus/thermo-range-workspace/thermo-range-ngivr/node_modules/node-addon-api/napi.h:2051:0,
                 from /home/patrikx3/Projects/sygnus/thermo-range-workspace/thermo-range-ngivr/native/pi-worker.cc:1:
/home/patrikx3/Projects/sygnus/thermo-range-workspace/thermo-range-ngivr/node_modules/node-addon-api/napi-inl.h:1814:13: note: candidate: void Napi::Promise::Deferred::Reject(napi_value) const
 inline void Promise::Deferred::Reject(napi_value value) const {
             ^~~~~~~
/home/patrikx3/Projects/sygnus/thermo-range-workspace/thermo-range-ngivr/node_modules/node-addon-api/napi-inl.h:1814:13: note:   no known conversion for argument 1 from ‘const Napi::Error’ to ‘napi_value {aka napi_value__*}’
CMakeFiles/thermo.dir/build.make:86: recipe for target 'CMakeFiles/thermo.dir/native/pi-worker.cc.o' failed
make[2]: *** [CMakeFiles/thermo.dir/native/pi-worker.cc.o] Error 1
CMakeFiles/Makefile2:67: recipe for target 'CMakeFiles/thermo.dir/all' failed
make[1]: *** [CMakeFiles/thermo.dir/all] Error 2
Makefile:83: recipe for target 'all' failed
make: *** [all] Error 2
ERR! OMG Process terminated: 2

that is why i cannot pass from c++ to nodejs with promises.

sorry i do not use callbacks anymore, only promises.

the full code is:

#include <napi.h>
#include "pi-worker.h"  // NOLINT(build/include)
#include <math.h>

class PiWorker : public Napi::AsyncWorker {
public:
    PiWorker(Napi::Env &env, Napi::Promise::Deferred &deferred, int points)
            : Napi::AsyncWorker(env), deferred(deferred), estimate(0), points(points) {}

    ~PiWorker() {}

    // Executed inside the worker-thread.
    // It is not safe to access JS engine data structure
    // here, so everything we need for input and output
    // should go on `this`.
    void Execute() {
        int count = 0;
        for (int i = 0; i < points; ++i) {
            float x = float(rand()) / RAND_MAX;
            float y = float(rand()) / RAND_MAX;
            if (sqrt(x * x + y * y) < 1)
                count++;
        }
        estimate = 4.0 * count / points;

        // you could handle errors as well
        // throw std::runtime_error("test error");
        // or like
        // Napi::AsyncWorker::SetError("test error");
    }

    // Executed when the async work is complete
    // this function will be run inside the main event loop
    // so it is safe to use JS engine data again
    void OnOK() {
        deferred.Resolve(Napi::Number::New(Env(), estimate));
    }

    void OnError(Napi::Error const &error) {
        deferred.Reject(error.Value());
    }

private:
    int points;
    double estimate;
    Napi::Promise::Deferred& deferred;
};

Napi::Value CalculatePiAsync(const Napi::CallbackInfo &info) {
    Napi::Env env = info.Env();

    int points = info[0].As<Napi::Number>().Uint32Value();

    Napi::Promise::Deferred deferred = Napi::Promise::Deferred::New(env);

    PiWorker *piWorker = new PiWorker(env, deferred, points);
    piWorker->Queue();
    return deferred.Promise();
}