Skip to content

Commit

Permalink
doc: improve documentation on argument validation
Browse files Browse the repository at this point in the history
PR-URL: nodejs#56954
Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
Reviewed-By: Ulises Gascón <ulisesgascongonzalez@gmail.com>
  • Loading branch information
Aditi-1400 authored Feb 14, 2025
1 parent e4f2c25 commit f208027
Showing 1 changed file with 62 additions and 0 deletions.
62 changes: 62 additions & 0 deletions src/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -589,6 +589,68 @@ void InitializeHttpParser(Local<Object> target,
}
```
### Argument validation in public APIs vs. internal code
#### Public API argument sanitization
When arguments come directly from user code, Node.js will typically validate them at the
JavaScript layer and throws user-friendly
[errors](https://github.com/nodejs/node/blob/main/doc/contributing/using-internal-errors.md)
(e.g., `ERR_INVALID_*`), if they are invalid. This helps end users
quickly understand and fix mistakes in their own code.
This approach ensures that the error message pinpoints which argument is wrong
and how it should be fixed. Additionally, problems in user code do not cause
mysterious crashes or hard-to-diagnose failures deeper in the engine.
Example from `zlib.js`:
```js
function crc32(data, value = 0) {
if (typeof data !== 'string' && !isArrayBufferView(data)) {
throw new ERR_INVALID_ARG_TYPE('data', ['Buffer', 'TypedArray', 'DataView','string'], data);
}
validateUint32(value, 'value');
return crc32Native(data, value);
}
```

The corresponding C++ assertion code for the above example from it's binding `node_zlib.cc`:

```cpp
CHECK(args[0]->IsArrayBufferView() || args[0]->IsString());
CHECK(args[1]->IsUint32());
```
#### Internal code and C++ binding checks
Inside Node.js’s internal layers, especially the C++ [binding function][]s
typically assume their arguments have already been checked and sanitized
by the upper-level (JavaScript) callers. As a result, internal C++ code
often just uses `CHECK()` or similar assertions to confirm that the
types/values passed in are correct. If that assertion fails, Node.js will
crash or abort with an internal diagnostic message. This is to avoid
re-validating every internal function argument repeatedly which can slow
down the system.
However, in a less common case where the API is implemented completely in
C++, the arguments would be validated directly in C++, with the errors
thrown using `THROW_ERR_INVALID_*` macros from `src/node_errors.h`.
For example in `worker_threads.moveMessagePortToContext`:
```cpp
void MessagePort::MoveToContext(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
if (!args[0]->IsObject() ||
!env->message_port_constructor_template()->HasInstance(args[0])) {
return THROW_ERR_INVALID_ARG_TYPE(env,
"The \"port\" argument must be a MessagePort instance");
}
// ...
}
```

<a id="exception-handling"></a>

### Exception handling
Expand Down

0 comments on commit f208027

Please # to comment.