• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Error Handling Using Node-API
2
3## Introduction
4
5Node-API provides APIs for handling errors occurred in ArkTS code via exceptions. Properly using these APIs helps improve module stability and reliability.
6
7## Basic Concepts
8
9Exceptions and errors are common concepts in ArkTS programming. An exception indicates the presence of an unexpected condition, and an error indicates that the application cannot perform certain operations correctly. Node-API provides a set of APIs for handling errors occurred in ArkTS code via exceptions. Read on the following to learn basic concepts related to error handling:
10
11- Exception: indicates an unexpected condition that may occur during the execution of an application. It can be a syntax error, runtime error, or logic error. For example, the division of a non-zero value with zero and an operation on undefined variables are exceptions.
12- Error: indicates that the application cannot perform some operations. Errors can be defined by the underlying system, API, or developer.
13- **TypeError**: indicates that the type of an operation or value does not meet the expectation. Generally, this error is caused by an incorrect data type.
14- **RangeError**: indicates that a value is not in the expected range. For example, an index beyond the array length is accessed.
15
16These concepts are important in exception and error handling. Properly using methods to capture, handle, or report exceptions and errors help improve application stability.
17
18## Available APIs
19
20The following table lists the APIs provided by the Node-API module for handling ArkTS errors and exceptions in C/C++.
21| API| Description|
22| -------- | -------- |
23| napi_create_error, napi_create_type_error, napi_create_range_error| Creates an error, which can be thrown to ArkTS using **napi_throw**.|
24| napi_throw | Throws the ArkTS error object created by **napi_create_error** or obtained by **napi_get_last_error_info**.|
25| napi_throw_error, napi_throw_type_error, napi_throw_range_error| Throws an ArkTS error occurred in C/C++.|
26| napi_is_error | Checks whether a **napi_value** is an error object.|
27| napi_get_and_clear_last_exception | Obtains and clears the latest exception.|
28| napi_is_exception_pending | Checks whether there is a pending exception.|
29| napi_fatal_error | Raises a fatal error to terminate the process immediately.|
30| napi_fatal_exception | Throws a fatal exception, terminates the process, and generates a crash log.|
31
32## Example
33
34If you are just starting out with Node-API, see [Node-API Development Process](use-napi-process.md). The following demonstrates only the C++ and ArkTS code involved in the APIs for error handling.
35
36### napi_get_last_error_info
37
38Call **napi_get_last_error_info** to obtain the last error information, including the error code, error message, and stack information. This API can also be used to handle pending ArkTS exceptions.
39
40CPP code:
41
42```cpp
43#include "napi/native_api.h"
44static napi_value GetLastErrorInfo(napi_env env, napi_callback_info info)
45{
46    // Obtain the input parameter, that is the message string in this example.
47    size_t argc = 1;
48    napi_value args[1] = {nullptr};
49    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
50    // Call napi_get_value_int32 to obtain the input string parameter to create an error.
51    int32_t value = 0;
52    napi_status status = napi_get_value_int32(env, args[0], &value);
53    // The return value (status) is not napi_ok, which means an error occurred.
54    if (status != napi_ok) {
55        OH_LOG_INFO(LOG_APP, "Test Node-API napi_get_value_int32 return status, status is not equal to napi_ok.");
56    }
57
58    // Call napi_get_last_error_info to obtain the last error message.
59    const napi_extended_error_info *errorInfo;
60    napi_get_last_error_info(env, &errorInfo);
61    // Obtain the error code and compare it with the return value (status) obtained.
62    if (errorInfo->error_code == status) {
63        OH_LOG_INFO(LOG_APP, "Test Node-API napi_get_last_error_info return errorInfo, error_code equal to status.");
64    }
65
66    // Obtain the error message as the return value and print it.
67    napi_value result = nullptr;
68    napi_create_string_utf8(env, errorInfo->error_message, NAPI_AUTO_LENGTH, &result);
69    return result;
70}
71```
72
73API declaration:
74
75```ts
76// index.d.ts
77export const getLastErrorInfo: (str: string) => string;
78```
79
80ArkTS code:
81
82```ts
83import hilog from '@ohos.hilog';
84import testNapi from 'libentry.so';
85try {
86  hilog.info(0x0000, 'testTag', 'Test Node-API napi_get_last_error_info: %{public}s', testNapi.getLastErrorInfo('message'));
87} catch (error) {
88  hilog.error(0x0000, 'testTag', 'Test Node-API napi_get_last_error_info error: %{public}s', error);
89}
90```
91
92### napi_create_type_error
93
94Call **napi_create_type_error** to create an ArkTS **TypeError** object with text information.
95
96CPP code:
97
98```cpp
99#include "napi/native_api.h"
100
101static napi_value CreateTypeError(napi_env env, napi_callback_info info)
102{
103    // Construct errorCode and errorMessage.
104    napi_value errorCode = nullptr;
105    napi_create_string_utf8(env, "napi_create_error errorCode", NAPI_AUTO_LENGTH, &errorCode);
106    napi_value errorMessage = nullptr;
107    napi_create_string_utf8(env, "napi_create_error errorMessage", NAPI_AUTO_LENGTH, &errorMessage);
108    // Call napi_create_type_error to create a typeError object.
109    napi_value error = nullptr;
110    napi_create_type_error(env, errorCode, errorMessage, &error);
111    return error;
112}
113```
114
115API declaration:
116
117```ts
118// index.d.ts
119export const createTypeError: () => Error;
120```
121
122ArkTS code:
123
124```ts
125import hilog from '@ohos.hilog';
126import testNapi from 'libentry.so';
127try {
128  throw testNapi.createTypeError();
129} catch (error) {
130  hilog.error(0x0000, 'testTag', 'Test Node-API napi_create_type_error errorCode: %{public}s, errorMessage %{public}s', error.code, error.message);
131}
132```
133
134### napi_create_range_error
135
136Call **napi_create_range_error** to create an ArkTS **RangeError** with text information.
137
138CPP code:
139
140```cpp
141#include "napi/native_api.h"
142
143static napi_value CreateRangeError(napi_env env, napi_callback_info info)
144{
145    // Construct errorCode and errorMessage.
146    napi_value errorCode = nullptr;
147    napi_create_string_utf8(env, "napi_create_error errorCode", NAPI_AUTO_LENGTH, &errorCode);
148    napi_value errorMessage = nullptr;
149    napi_create_string_utf8(env, "napi_create_error errorMessage", NAPI_AUTO_LENGTH, &errorMessage);
150    // Call napi_create_range_error to create a typeError object.
151    napi_value error = nullptr;
152    napi_create_range_error(env, errorCode, errorMessage, &error);
153    return error;
154}
155```
156
157API declaration:
158
159```ts
160// index.d.ts
161export const createRangeError: () => Error;
162```
163
164ArkTS code:
165
166```ts
167import hilog from '@ohos.hilog';
168import testNapi from 'libentry.so';
169try {
170  throw testNapi.createRangeError();
171} catch (error) {
172  hilog.error(0x0000, 'testTag', 'Test Node-API napi_create_range_error errorCode: %{public}s, errorMessage: %{public}s', error.code, error.message);
173}
174```
175
176### napi_create_error
177
178Call **napi_create_error** to create an ArkTS error object with text information.
179
180### napi_throw
181
182Call **napi_throw** to throw an ArkTS exception. You need to create an error object first and pass it to **napi_throw**. You can use this API to throw an ArkTS exception that indicates an error or unexpected behavior occurred in the native code so that exception can be captured and handled.
183
184CPP code:
185
186```cpp
187#include "napi/native_api.h"
188
189static napi_value NapiThrow(napi_env env, napi_callback_info info)
190{
191    // Perform the following operations to throw an exception to indicate an error occurred:
192    // Create a string in the Node-API environment and store it in the errorCode variable.
193    napi_value errorCode = nullptr;
194    napi_create_string_utf8(env, "throw errorCode", NAPI_AUTO_LENGTH, &errorCode);
195    // Create a string in the Node-API environment and store it in the errorMessage variable.
196    napi_value errorMessage = nullptr;
197    napi_create_string_utf8(env, "throw errorMessage", NAPI_AUTO_LENGTH, &errorMessage);
198    // Create an ArkTS error object.
199    napi_value error = nullptr;
200    napi_create_error(env, errorCode, errorMessage, &error);
201    // Call napi_throw to throw an error.
202    napi_throw(env, error);
203    return nullptr;
204}
205```
206
207API declaration:
208
209```ts
210// index.d.ts
211export const napiThrow: () => void;
212```
213
214ArkTS code:
215
216```ts
217import hilog from '@ohos.hilog';
218import testNapi from 'libentry.so';
219try {
220  testNapi.napiThrow();
221} catch (error) {
222  hilog.error(0x0000, 'testTag', 'Test Node-API napi_throw errorCode: %{public}s, errorMessage: %{public}s', error.code, error.message);
223}
224```
225
226### napi_throw_error
227
228Call **napi_throw_error** to throw an ArkTS **Error** object with text information.
229
230CPP code:
231
232```cpp
233#include "napi/native_api.h"
234
235// Throw an error with an error message.
236static napi_value NapiThrowErrorMessage(napi_env env, napi_callback_info info)
237{
238    napi_throw_error(env, nullptr, "napi_throw_error throwing an error");
239    return nullptr;
240}
241// Pass in two parameters. Throw an error when the second parameter, that is, the divisor, is 0.
242static napi_value NapiThrowError(napi_env env, napi_callback_info info)
243{
244    // Pass two parameters from ArkTS.
245    size_t argc = 2;
246    napi_value argv[2] = {nullptr};
247    napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
248    // Convert the two parameters to values of the double type as the dividend and divisor.
249    double dividend, divisor;
250    napi_get_value_double(env, argv[0], &dividend);
251    napi_get_value_double(env, argv[1], &divisor);
252    // If the divisor is 0, throw an error with the error code of DIVIDE_BY_ZERO and the error message of Cannot divide by zero.
253    if (divisor == 0) {
254        napi_throw_error(env, "DIVIDE_BY_ZERO", "Cannot divide by zero");
255    }
256    return nullptr;
257}
258```
259
260API declaration:
261
262```ts
263// index.d.ts
264export const napiThrowErrorMessage: () => void;
265export const napiThrowError: (dividend: number, divisor: number) => void;
266```
267
268ArkTS code:
269
270```ts
271import hilog from '@ohos.hilog';
272import testNapi from 'libentry.so';
273try {
274  testNapi.napiThrowErrorMessage();
275} catch (error) {
276  hilog.error(0x0000, 'testTag', 'Test Node-API napi_throw_error error code: %{public}s , message: %{public}s', error.code, error.message);
277}
278try {
279  testNapi.napiThrowError(5, 0);
280} catch (error) {
281  hilog.error(0x0000, 'testTag', 'Test Node-API napi_throw_error errorCode: %{public}s , errorManager: %{public}s', error.code, error.message);
282}
283```
284
285### napi_throw_type_error
286
287Call **napi_throw_type_error** to throw an ArkTS **TypeError** object with text information.
288
289CPP code:
290
291```cpp
292#include "napi/native_api.h"
293
294// Throw a type error with an error message.
295static napi_value ThrowTypeErrorMessage(napi_env env, napi_callback_info info)
296{
297    napi_throw_type_error(env, nullptr, "napi_throw_type_error throwing an error");
298    return nullptr;
299}
300// Pass in a parameter of incorrect type. Throw a type error when the parameter type is found incorrect.
301static napi_value ThrowTypeError(napi_env env, napi_callback_info info)
302{
303    // Pass a parameter from ArkTS.
304    size_t argc = 1;
305    napi_value argv[1] = {nullptr};
306    napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
307    // Convert the input parameter to a value of the napi_valuetype type.
308    napi_valuetype valueType;
309    napi_typeof(env, argv[0], &valueType);
310    // Throw a type error if the input parameter is not of the napi_number type.
311    if (valueType != napi_number) {
312        // Throw a type error with both errorCode and errorMessage.
313        napi_throw_type_error(env, "napi_throw_type_error", "Argument must be a number");
314    }
315    return nullptr;
316}
317```
318
319API declaration:
320
321```ts
322// index.d.ts
323export const throwTypeErrorMessage: () => void;
324export const throwTypeError: (message: string) => void;
325```
326
327ArkTS code:
328
329```ts
330import hilog from '@ohos.hilog';
331import testNapi from 'libentry.so';
332try {
333  testNapi.throwTypeErrorMessage();
334} catch (error) {
335  hilog.error(0x0000, 'testTag', 'Test Node-API napi_throw_type_error errorCode: %{public}s, errorMessage: %{public}s', error.code, error.message);
336}
337try {
338  testNapi.throwTypeError('str');
339} catch (error) {
340  hilog.error(0x0000, 'testTag', 'Test Node-API napi_throw_type_error errorCode: %{public}s, errorMessage: %{public}s', error.code, error.message);
341}
342```
343
344### napi_throw_range_error
345
346Call **napi_create_range_error** to create an ArkTS **RangeError** with text information.
347
348CPP code:
349
350```cpp
351#include "napi/native_api.h"
352
353// Throw a range error with an error message.
354static napi_value ThrowRangeErrorMessage(napi_env env, napi_callback_info info)
355{
356    napi_throw_range_error(env, nullptr, "napi_throw_range_error one");
357    return nullptr;
358}
359// Pass in parameters of incorrect quantity and throw a range error.
360static napi_value ThrowRangeError(napi_env env, napi_callback_info info)
361{
362    // Pass two parameters from ArkTS.
363    size_t argc = 2;
364    napi_value argv[2] = {nullptr};
365    napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
366    // If the number of parameters is not 2,
367    if (argc != 2) {
368        // Throw a range error.
369        napi_throw_range_error(env, "napi_throw_range_error", "Expected two numbers as arguments");
370        return nullptr;
371    }
372    // Add the two input values and return the result.
373    double numOne = 0;
374    double numTwo = 0;
375    napi_get_value_double(env, argv[0], &numOne);
376    napi_get_value_double(env, argv[1], &numTwo);
377    double result = numOne + numTwo;
378    napi_value resultValue;
379    napi_create_double(env, result, &resultValue);
380    return resultValue;
381}
382```
383
384API declaration:
385
386```ts
387// index.d.ts
388export const throwRangeErrorMessage: () => void;
389export const throwRangeError: (num: number) => number | void;
390```
391
392ArkTS code:
393
394```ts
395import hilog from '@ohos.hilog';
396import testNapi from 'libentry.so';
397try {
398  testNapi.throwRangeErrorMessage();
399} catch (error) {
400  hilog.error(0x0000, 'testTag', 'Test Node-API napi_throw_range_error errorCode: %{public}s, errorMessage: %{public}s', error.code, error.message);
401}
402
403try {
404  testNapi.throwRangeError(1);
405} catch (error) {
406  hilog.error(0x0000, 'testTag', 'Test Node-API napi_throw_range_error errorCode: %{public}s, errorMessage: %{public}s', error.code, error.message);
407}
408```
409
410### napi_is_error
411
412Call **napi_is_error** to check whether the given **napi_value** represents an error object.
413
414CPP code:
415
416```cpp
417#include "napi/native_api.h"
418
419static napi_value NapiIsError(napi_env env, napi_callback_info info)
420{
421    // Obtain the parameter passed in.
422    size_t argc = 1;
423    napi_value args[1] = {nullptr};
424    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
425    // Call napi_is_error to check whether the input parameter is an error object.
426    bool result = false;
427    // If napi_value is an error object, set result to true. Otherwise, set result to false.
428    napi_is_error(env, args[0], &result);
429    // Obtain result, call napi_get_boolean to convert result to napi_value, and return napi_value.
430    napi_value returnValue = nullptr;
431    napi_get_boolean(env, result, &returnValue);
432    return returnValue;
433}
434```
435
436API declaration:
437
438```ts
439// index.d.ts
440export const napiIsError: <T>(obj: T) => boolean;
441```
442
443ArkTS code:
444
445```ts
446import hilog from '@ohos.hilog';
447import testNapi from 'libentry.so';
448try {
449  throw new Error("throwing an error");
450} catch (error) {
451  hilog.error(0x0000, 'testTag', 'Test Node-API napi_is_error error: %{public}s', testNapi.napiIsError(error)
452    .toString());
453  hilog.error(0x0000, 'testTag', 'Test Node-API napi_is_error error: %{public}s', testNapi.napiIsError(1)
454    .toString());
455}
456```
457
458### napi_get_and_clear_last_exception
459
460Call **napi_get_and_clear_last_exception** to obtain and clear the last exception.
461
462CPP code:
463
464```cpp
465#include "napi/native_api.h"
466
467static napi_value GetAndClearLastException(napi_env env, napi_callback_info info)
468{
469    // Throw an error.
470    napi_throw_error(env, "napi_create_error errorCode", "napi_create_error errorMessage");
471    // Call napi_get_and_clear_last_exception to obtain and clear the last unhandled exception. This API can be called even if there are suspended ArkTS exceptions.
472    napi_value result = nullptr;
473    napi_status status = napi_get_and_clear_last_exception(env, &result);
474    if (status != napi_ok) {
475        return nullptr;
476    }
477    return result;
478}
479```
480
481API declaration:
482
483```ts
484// index.d.ts
485export const getAndClearLastException: () => Error | void;
486```
487
488ArkTS code:
489
490```ts
491import hilog from '@ohos.hilog';
492import testNapi from 'libentry.so';
493// Obtain the last unprocessed exception.
494hilog.info(0x0000, 'testTag', 'Test Node-API napi_get_and_clear_last_exception, error.message: %{public}s',
495           testNapi.getAndClearLastException());
496```
497
498### napi_is_exception_pending
499
500Call **napi_is_exception_pending** to check whether there is any pending exception.
501
502CPP code:
503
504```cpp
505#include "napi/native_api.h"
506
507static napi_value IsExceptionPending(napi_env env, napi_callback_info info)
508{
509    napi_status status;
510    bool isExceptionPending = false;
511    // Perform operations that may cause an error.
512    napi_throw_error(env, "napi_create_error errorCode", "napi_create_error errorMessage");
513    // Check whether there is a pending exception.
514    status = napi_is_exception_pending(env, &isExceptionPending);
515    if (status != napi_ok) {
516        return nullptr;
517    }
518    if (isExceptionPending) {
519        // Handle the pending exception.
520        napi_value result = nullptr;
521        status = napi_get_and_clear_last_exception(env, &result);
522        if (status != napi_ok) {
523            return nullptr;
524        }
525        // Return the result.
526        return result;
527    }
528    return nullptr;
529}
530```
531
532API declaration:
533
534```ts
535// index.d.ts
536export const isExceptionPending: () => Object | void;
537```
538
539ArkTS code:
540
541```ts
542import hilog from '@ohos.hilog';
543import testNapi from 'libentry.so';
544interface MyObject {
545  code: string;
546  message: string;
547}
548try {
549  let result = testNapi.isExceptionPending() as MyObject;
550  hilog.info(0x0000, 'testTag', 'Test Node-API napi_is_exception_pending, error.Code: %{public}s, error.message: %{public}s',
551    result.code, result.message);
552} catch (error) {
553  hilog.error(0x0000, 'testTag', 'Test Node-API napi_is_exception_pending error');
554}
555```
556
557### napi_fatal_error
558
559Call **napi_fatal_error** to raise a fatal error to terminate the process immediately. Calling **napi_fatal_error** will terminate the application immediately. Avoid frequently calling this API in during normal operations.
560
561CPP code:
562
563```cpp
564#include "napi/native_api.h"
565
566static napi_value FatalError(napi_env env, napi_callback_info info)
567{
568    // Calling napi_fatal_error will terminate the application process immediately. Use this API only when a fatal error that cannot be rectified occurs.
569    // Simulate a fatal error.
570    bool errorCondition = true;
571    if (errorCondition) {
572        // Create a fatal error.
573        napi_fatal_error("napi_fatal_error test", NAPI_AUTO_LENGTH, "napi_create_error errorMessage", NAPI_AUTO_LENGTH);
574    }
575    return nullptr;
576}
577```
578
579API declaration:
580
581```ts
582// index.d.ts
583export const fatalError: () => void;
584```
585
586ArkTS code:
587
588```ts
589import hilog from '@ohos.hilog';
590import testNapi from 'libentry.so';
591try {
592  testNapi.fatalError();
593} catch (error) {
594  hilog.error(0x0000, 'testTag', 'Test Node-API napi_fatal_error error');
595}
596```
597
598### napi_fatal_exception
599Call **napi_fatal_exception** in the context of the main thread to throw a fatal exception. As a result, the application is terminated and a crash log is generated. Exercise caution when using this API. Avoid frequently calling this API during normal operations.
600
601CPP code:
602
603```cpp
604#include "napi/native_api.h"
605
606static napi_value FatalException(napi_env env, napi_callback_info info)
607{
608    size_t argc = 1;
609    napi_value args[1] = {nullptr};
610
611    napi_status status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
612    if (status != napi_ok) {
613      return nullptr;
614    }
615    // Calling napi_fatal_exception will terminate the application process. Use this API only when a fatal error that cannot be rectified occurs in the main thread.
616    // Simulate a fatal error.
617    status = napi_fatal_exception(env, args[0]);
618    if (status != napi_ok) {
619      return nullptr;
620    }
621    return nullptr;
622}
623```
624
625API declaration:
626
627```ts
628// index.d.ts
629export const fatalException: (err: Error) => void;
630```
631
632ArkTS code:
633
634```ts
635import hilog from '@ohos.hilog';
636import testNapi from 'libentry.so';
637
638const err = new Error("a fatal exception occurred");
639testNapi.fatalException(err);
640```
641
642To print logs in the native CPP, add the following information to the **CMakeLists.txt** file and add the header file by using **#include "hilog/log.h"**.
643
644```text
645// CMakeLists.txt
646add_definitions( "-DLOG_DOMAIN=0xd0d0" )
647add_definitions( "-DLOG_TAG=\"testTag\"" )
648target_link_libraries(entry PUBLIC libhilog_ndk.z.so)
649```
650