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