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