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