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], ÷nd); 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