diff --git a/doc/api/errors.md b/doc/api/errors.md
index 62a62d76656223..c7ca32091ad3ac 100644
--- a/doc/api/errors.md
+++ b/doc/api/errors.md
@@ -1090,6 +1090,12 @@ A callback function was required but was not been provided to a Node.js API.
Invalid characters were detected in headers.
+
+### ERR_INVALID_CONSTRUCTOR_CALL
+
+A function that should not be invoked as a construcor was invoked with `new`
+or a constructor was invoked without `new`.
+
### ERR_INVALID_CURSOR_POS
@@ -1343,6 +1349,11 @@ An attempt was made to `require()` an [ES6 module][].
Script execution was interrupted by `SIGINT` (For example, when Ctrl+C was
pressed).
+
+### ERR_SCRIPT_EXECUTION_TIMEOUT
+
+Script execution timed out, possibly due to bugs in the script being executed.
+
### ERR_SERVER_ALREADY_LISTEN
diff --git a/src/env-inl.h b/src/env-inl.h
index 96e88b5c116adb..ce5d19fa125e81 100644
--- a/src/env-inl.h
+++ b/src/env-inl.h
@@ -657,6 +657,23 @@ inline void Environment::SetTemplateMethod(v8::Local that,
ENVIRONMENT_STRONG_PERSISTENT_PROPERTIES(V)
#undef V
+#define V(code, type) \
+ inline v8::Local Environment::code(const char* message) const { \
+ v8::Local js_code = OneByteString(isolate(), #code); \
+ v8::Local js_msg = OneByteString(isolate(), message); \
+ v8::Local e = \
+ v8::Exception::type(js_msg)->ToObject( \
+ isolate()->GetCurrentContext()).ToLocalChecked(); \
+ e->Set(code_string(), js_code); \
+ return e; \
+ } \
+ \
+ inline void Environment::THROW_ ## code(const char* message) const { \
+ isolate()->ThrowException(code(message)); \
+ }
+ ENVIRONMENT_ERROR_HELPERS(V)
+#undef V
+
} // namespace node
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
diff --git a/src/env.h b/src/env.h
index a688b069242160..68fc4fda139c11 100644
--- a/src/env.h
+++ b/src/env.h
@@ -343,6 +343,21 @@ struct PackageConfig {
V(url_constructor_function, v8::Function) \
V(write_wrap_template, v8::ObjectTemplate)
+#define ENVIRONMENT_ERROR_HELPERS(V) \
+ V(ERR_BUFFER_OUT_OF_BOUNDS, RangeError) \
+ V(ERR_INDEX_OUT_OF_RANGE, RangeError) \
+ V(ERR_INSPECTOR_ALREADY_CONNECTED, Error) \
+ V(ERR_INVALID_ARG_VALUE, Error) \
+ V(ERR_INVALID_ARG_TYPE, TypeError) \
+ V(ERR_INVALID_CALLBACK, TypeError) \
+ V(ERR_INVALID_CONSTRUCTOR_CALL, TypeError) \
+ V(ERR_INVALID_THIS, TypeError) \
+ V(ERR_MISSING_ARGS, TypeError) \
+ V(ERR_MISSING_MODULE, Error) \
+ V(ERR_OUT_OF_RANGE, RangeError) \
+ V(ERR_SCRIPT_EXECUTION_INTERRUPTED, Error) \
+ V(ERR_SCRIPT_EXECUTION_TIMEOUT, Error)
+
class Environment;
class IsolateData {
@@ -716,6 +731,12 @@ class Environment {
ENVIRONMENT_STRONG_PERSISTENT_PROPERTIES(V)
#undef V
+#define V(code, _) \
+ inline v8::Local code(const char* message) const; \
+ inline void THROW_ ## code(const char* message) const;
+ ENVIRONMENT_ERROR_HELPERS(V)
+#undef V
+
#if HAVE_INSPECTOR
inline inspector::Agent* inspector_agent() const {
return inspector_agent_.get();
diff --git a/src/module_wrap.cc b/src/module_wrap.cc
index 617bae8b60e3e0..f8639c6a9cb2f0 100644
--- a/src/module_wrap.cc
+++ b/src/module_wrap.cc
@@ -81,19 +81,20 @@ void ModuleWrap::New(const FunctionCallbackInfo& args) {
Isolate* isolate = args.GetIsolate();
if (!args.IsConstructCall()) {
- env->ThrowError("constructor must be called using new");
+ env->THROW_ERR_INVALID_CONSTRUCTOR_CALL(
+ "constructor must be called using new");
return;
}
if (!args[0]->IsString()) {
- env->ThrowError("first argument is not a string");
+ env->THROW_ERR_INVALID_ARG_TYPE("first argument is not a string");
return;
}
Local source_text = args[0].As();
if (!args[1]->IsString()) {
- env->ThrowError("second argument is not a string");
+ env->THROW_ERR_INVALID_ARG_TYPE("second argument is not a string");
return;
}
@@ -162,7 +163,7 @@ void ModuleWrap::Link(const FunctionCallbackInfo& args) {
Environment* env = Environment::GetCurrent(args);
Isolate* isolate = args.GetIsolate();
if (!args[0]->IsFunction()) {
- env->ThrowError("first argument is not a function");
+ env->THROW_ERR_INVALID_ARG_TYPE("first argument is not a function");
return;
}
@@ -283,9 +284,10 @@ void ModuleWrap::Evaluate(const FunctionCallbackInfo& args) {
// which this timeout is nested, so check whether one of the watchdogs
// from this invocation is responsible for termination.
if (timed_out) {
- env->ThrowError("Script execution timed out.");
+ env->THROW_ERR_SCRIPT_EXECUTION_TIMEOUT("Script execution timed out.");
} else if (received_signal) {
- env->ThrowError("Script execution interrupted.");
+ env->THROW_ERR_SCRIPT_EXECUTION_INTERRUPTED(
+ "Script execution interrupted.");
}
env->isolate()->CancelTerminateExecution();
}
@@ -666,37 +668,39 @@ void ModuleWrap::Resolve(const FunctionCallbackInfo& args) {
Environment* env = Environment::GetCurrent(args);
if (args.IsConstructCall()) {
- env->ThrowError("resolve() must not be called as a constructor");
+ env->THROW_ERR_INVALID_CONSTRUCTOR_CALL(
+ "resolve() must not be called as a constructor");
return;
}
if (args.Length() != 2) {
- env->ThrowError("resolve must have exactly 2 arguments (string, string)");
+ env->THROW_ERR_INVALID_ARG_TYPE(
+ "resolve must have exactly 2 arguments (string, string)");
return;
}
if (!args[0]->IsString()) {
- env->ThrowError("first argument is not a string");
+ env->THROW_ERR_INVALID_ARG_TYPE("first argument is not a string");
return;
}
Utf8Value specifier_utf8(env->isolate(), args[0]);
std::string specifier_std(*specifier_utf8, specifier_utf8.length());
if (!args[1]->IsString()) {
- env->ThrowError("second argument is not a string");
+ env->THROW_ERR_INVALID_ARG_TYPE("second argument is not a string");
return;
}
Utf8Value url_utf8(env->isolate(), args[1]);
URL url(*url_utf8, url_utf8.length());
if (url.flags() & URL_FLAGS_FAILED) {
- env->ThrowError("second argument is not a URL string");
+ env->THROW_ERR_INVALID_ARG_TYPE("second argument is not a URL string");
return;
}
Maybe result = node::loader::Resolve(env, specifier_std, url);
if (result.IsNothing() || (result.FromJust().flags() & URL_FLAGS_FAILED)) {
std::string msg = "Cannot find module " + specifier_std;
- env->ThrowError(msg.c_str());
+ env->THROW_ERR_MISSING_MODULE(msg.c_str());
return;
}
@@ -749,7 +753,7 @@ void ModuleWrap::SetImportModuleDynamicallyCallback(
Environment* env = Environment::GetCurrent(args);
HandleScope handle_scope(iso);
if (!args[0]->IsFunction()) {
- env->ThrowError("first argument is not a function");
+ env->THROW_ERR_INVALID_ARG_TYPE("first argument is not a function");
return;
}
@@ -782,7 +786,7 @@ void ModuleWrap::SetInitializeImportMetaObjectCallback(
Environment* env = Environment::GetCurrent(args);
Isolate* isolate = env->isolate();
if (!args[0]->IsFunction()) {
- env->ThrowError("first argument is not a function");
+ env->THROW_ERR_INVALID_ARG_TYPE("first argument is not a function");
return;
}
diff --git a/src/node.cc b/src/node.cc
index b5084331156bb6..ce80c4a70d2dea 100644
--- a/src/node.cc
+++ b/src/node.cc
@@ -1577,7 +1577,7 @@ static void Chdir(const FunctionCallbackInfo& args) {
Environment* env = Environment::GetCurrent(args);
if (args.Length() != 1 || !args[0]->IsString()) {
- return env->ThrowTypeError("Bad argument.");
+ return env->THROW_ERR_INVALID_ARG_TYPE("Bad argument.");
}
node::Utf8Value path(args.GetIsolate(), args[0]);
@@ -1619,7 +1619,8 @@ static void Umask(const FunctionCallbackInfo& args) {
old = umask(0);
umask(static_cast(old));
} else if (!args[0]->IsInt32() && !args[0]->IsString()) {
- return env->ThrowTypeError("argument must be an integer or octal string.");
+ return env->THROW_ERR_INVALID_ARG_TYPE(
+ "argument must be an integer or octal string.");
} else {
int oct;
if (args[0]->IsInt32()) {
@@ -1632,7 +1633,7 @@ static void Umask(const FunctionCallbackInfo& args) {
for (size_t i = 0; i < str.length(); i++) {
char c = (*str)[i];
if (c > '7' || c < '0') {
- return env->ThrowTypeError("invalid octal string");
+ return env->THROW_ERR_INVALID_ARG_VALUE("invalid octal string");
}
oct *= 8;
oct += c - '0';
@@ -1776,7 +1777,8 @@ static void SetGid(const FunctionCallbackInfo& args) {
Environment* env = Environment::GetCurrent(args);
if (!args[0]->IsUint32() && !args[0]->IsString()) {
- return env->ThrowTypeError("setgid argument must be a number or a string");
+ return env->THROW_ERR_INVALID_ARG_TYPE(
+ "setgid argument must be a number or a string");
}
gid_t gid = gid_by_name(env->isolate(), args[0]);
@@ -1795,7 +1797,8 @@ static void SetEGid(const FunctionCallbackInfo& args) {
Environment* env = Environment::GetCurrent(args);
if (!args[0]->IsUint32() && !args[0]->IsString()) {
- return env->ThrowTypeError("setegid argument must be a number or string");
+ return env->THROW_ERR_INVALID_ARG_TYPE(
+ "setegid argument must be a number or string");
}
gid_t gid = gid_by_name(env->isolate(), args[0]);
@@ -1814,7 +1817,8 @@ static void SetUid(const FunctionCallbackInfo& args) {
Environment* env = Environment::GetCurrent(args);
if (!args[0]->IsUint32() && !args[0]->IsString()) {
- return env->ThrowTypeError("setuid argument must be a number or a string");
+ return env->THROW_ERR_INVALID_ARG_TYPE(
+ "setuid argument must be a number or a string");
}
uid_t uid = uid_by_name(env->isolate(), args[0]);
@@ -1833,7 +1837,8 @@ static void SetEUid(const FunctionCallbackInfo& args) {
Environment* env = Environment::GetCurrent(args);
if (!args[0]->IsUint32() && !args[0]->IsString()) {
- return env->ThrowTypeError("seteuid argument must be a number or string");
+ return env->THROW_ERR_INVALID_ARG_TYPE(
+ "seteuid argument must be a number or string");
}
uid_t uid = uid_by_name(env->isolate(), args[0]);
@@ -1890,7 +1895,7 @@ static void SetGroups(const FunctionCallbackInfo& args) {
Environment* env = Environment::GetCurrent(args);
if (!args[0]->IsArray()) {
- return env->ThrowTypeError("argument 1 must be an array");
+ return env->THROW_ERR_INVALID_ARG_TYPE("argument 1 must be an array");
}
Local groups_list = args[0].As();
@@ -1921,11 +1926,13 @@ static void InitGroups(const FunctionCallbackInfo& args) {
Environment* env = Environment::GetCurrent(args);
if (!args[0]->IsUint32() && !args[0]->IsString()) {
- return env->ThrowTypeError("argument 1 must be a number or a string");
+ return env->THROW_ERR_INVALID_ARG_TYPE(
+ "argument 1 must be a number or a string");
}
if (!args[1]->IsUint32() && !args[1]->IsString()) {
- return env->ThrowTypeError("argument 2 must be a number or a string");
+ return env->THROW_ERR_INVALID_ARG_TYPE(
+ "argument 2 must be a number or a string");
}
node::Utf8Value arg0(env->isolate(), args[0]);
@@ -2040,7 +2047,7 @@ static void Kill(const FunctionCallbackInfo& args) {
Environment* env = Environment::GetCurrent(args);
if (args.Length() != 2) {
- return env->ThrowError("Bad argument.");
+ return env->THROW_ERR_MISSING_ARGS("Bad argument.");
}
int pid = args[0]->Int32Value();
@@ -2238,13 +2245,13 @@ static void DLOpen(const FunctionCallbackInfo& args) {
CHECK_EQ(modpending, nullptr);
if (args.Length() < 2) {
- env->ThrowError("process.dlopen needs at least 2 arguments.");
+ env->THROW_ERR_MISSING_ARGS("process.dlopen needs at least 2 arguments.");
return;
}
int32_t flags = DLib::kDefaultFlags;
if (args.Length() > 2 && !args[2]->Int32Value(context).To(&flags)) {
- return env->ThrowTypeError("flag argument must be an integer.");
+ return env->THROW_ERR_INVALID_ARG_TYPE("flag argument must be an integer.");
}
Local