Skip to content

Fix reporting of API error messages #43

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 6, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions napi-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -1373,17 +1373,17 @@ inline void Buffer<T>::EnsureInfo() const {
inline Error Error::New(napi_env env) {
napi_status status;
napi_value error = nullptr;
if (Napi::Env(env).IsExceptionPending()) {
status = napi_get_and_clear_last_exception(env, &error);
assert(status == napi_ok);
}
else {
// No JS exception is pending, so check for NAPI error info.
const napi_extended_error_info* info;
status = napi_get_last_error_info(env, &info);
assert(status == napi_ok);

if (status == napi_ok) {
const napi_extended_error_info* info;
status = napi_get_last_error_info(env, &info);
assert(status == napi_ok);

if (status == napi_ok) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this make sense? assert + then make the code conditional on asserted statement?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we encounter another error while handling an error, there's not much we can do. Probably it should be a fatal error, except we haven't exposed node::FatalError() via N-API yet. The assert will at least indicate when something went wrong in a debug build, but in a release build the conditional allows it to continue without crashing.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This came up last time this code was reviewed: #32 (comment)

Probably we should go ahead and add a napi_fatal_error() API.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I opened a new issue to track this: #48
I don't think the current PR needs to be blocked by it.

if (info->error_code == napi_pending_exception) {
status = napi_get_and_clear_last_exception(env, &error);
assert(status == napi_ok);
}
else {
const char* error_message = info->error_message != nullptr ?
info->error_message : "Error in native callback";
napi_value message;
Expand Down
2 changes: 1 addition & 1 deletion src/node_api.cc
Original file line number Diff line number Diff line change
Expand Up @@ -755,7 +755,7 @@ napi_status napi_get_last_error_info(napi_env env,
error_messages[env->last_error.error_code];

*result = &(env->last_error);
return napi_clear_last_error(env);
return napi_ok;
}

napi_status napi_create_function(napi_env env,
Expand Down
10 changes: 8 additions & 2 deletions test/error.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@ using namespace Napi;

namespace {

void ThrowError(const CallbackInfo& info) {
void ThrowApiError(const CallbackInfo& info) {
// Attempting to call an empty function value will throw an API error.
Function(info.Env(), nullptr).Call({});
}

void ThrowJSError(const CallbackInfo& info) {
std::string message = info[0].As<String>().Utf8Value();
throw Error::New(info.Env(), message);
}
Expand Down Expand Up @@ -76,7 +81,8 @@ void CatchAndRethrowErrorThatEscapesScope(const CallbackInfo& info) {

Object InitError(Env env) {
Object exports = Object::New(env);
exports["throwError"] = Function::New(env, ThrowError);
exports["throwApiError"] = Function::New(env, ThrowApiError);
exports["throwJSError"] = Function::New(env, ThrowJSError);
exports["throwTypeError"] = Function::New(env, ThrowTypeError);
exports["throwRangeError"] = Function::New(env, ThrowRangeError);
exports["catchError"] = Function::New(env, CatchError);
Expand Down
6 changes: 5 additions & 1 deletion test/error.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@ const buildType = process.config.target_defaults.default_configuration;
const binding = require(`./build/${buildType}/binding.node`);
const assert = require('assert');

assert.throws(() => binding.error.throwError('test'), err => {
assert.throws(() => binding.error.throwApiError('test'), err => {
return err instanceof Error && err.message.includes('Invalid');
});

assert.throws(() => binding.error.throwJSError('test'), err => {
return err instanceof Error && err.message === 'test';
});

Expand Down