@@ -589,6 +589,68 @@ void InitializeHttpParser(Local<Object> target,
589589}
590590```
591591
592+ ### Argument validation in public APIs vs. internal code
593+
594+ #### Public API argument sanitization
595+
596+ When arguments come directly from user code, Node.js will typically validate them at the
597+ JavaScript layer and throws user-friendly
598+ [errors](https://github.com/nodejs/node/blob/main/doc/contributing/using-internal-errors.md)
599+ (e.g., `ERR_INVALID_*`), if they are invalid. This helps end users
600+ quickly understand and fix mistakes in their own code.
601+
602+ This approach ensures that the error message pinpoints which argument is wrong
603+ and how it should be fixed. Additionally, problems in user code do not cause
604+ mysterious crashes or hard-to-diagnose failures deeper in the engine.
605+
606+ Example from `zlib.js`:
607+
608+ ```js
609+ function crc32(data, value = 0) {
610+ if (typeof data !== 'string' && !isArrayBufferView(data)) {
611+ throw new ERR_INVALID_ARG_TYPE('data', ['Buffer', 'TypedArray', 'DataView','string'], data);
612+ }
613+ validateUint32(value, 'value');
614+ return crc32Native(data, value);
615+ }
616+ ```
617+
618+ The corresponding C++ assertion code for the above example from it's binding ` node_zlib.cc ` :
619+
620+ ``` cpp
621+ CHECK (args[ 0] ->IsArrayBufferView() || args[ 0] ->IsString());
622+ CHECK(args[ 1] ->IsUint32());
623+ ```
624+
625+ #### Internal code and C++ binding checks
626+
627+ Inside Node.js’s internal layers, especially the C++ [binding function][]s
628+ typically assume their arguments have already been checked and sanitized
629+ by the upper-level (JavaScript) callers. As a result, internal C++ code
630+ often just uses `CHECK()` or similar assertions to confirm that the
631+ types/values passed in are correct. If that assertion fails, Node.js will
632+ crash or abort with an internal diagnostic message. This is to avoid
633+ re-validating every internal function argument repeatedly which can slow
634+ down the system.
635+
636+ However, in a less common case where the API is implemented completely in
637+ C++, the arguments would be validated directly in C++, with the errors
638+ thrown using `THROW_ERR_INVALID_*` macros from `src/node_errors.h`.
639+
640+ For example in `worker_threads.moveMessagePortToContext`:
641+
642+ ```cpp
643+ void MessagePort::MoveToContext(const FunctionCallbackInfo<Value>& args) {
644+ Environment* env = Environment::GetCurrent(args);
645+ if (!args[0]->IsObject() ||
646+ !env->message_port_constructor_template()->HasInstance(args[0])) {
647+ return THROW_ERR_INVALID_ARG_TYPE(env,
648+ "The \"port\" argument must be a MessagePort instance");
649+ }
650+ // ...
651+ }
652+ ```
653+
592654<a id =" exception-handling " ></a >
593655
594656### Exception handling
0 commit comments