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