On this page

在 Node.js 中运行的应用程序通常会遇到以下几类错误:

  • 标准 JavaScript 错误,例如 <EvalError><SyntaxError><RangeError><ReferenceError><TypeError><URIError>
  • 标准 DOMException
  • 由底层操作系统约束触发的系统错误,例如尝试打开不存在的文件或尝试通过关闭的套接字发送数据。
  • AssertionError 是一类特殊的错误,当 Node.js 检测到绝不应发生的异常逻辑违规时会触发。这些错误通常由 node:assert 模块抛出。
  • 应用程序代码触发的用户指定错误。

Node.js 抛出的所有 JavaScript 和系统错误都继承自标准 JavaScript <Error> 类,或是其实例,并保证提供 至少 该类上可用的属性。

Node.js 抛出的错误的 error.message 属性可能会在任何版本中更改。请使用 error.code 来识别错误。对于 DOMException,请使用 domException.name 来识别其类型。

Node.js 支持多种机制来传播和处理应用程序运行时发生的错误。这些错误的报告和如何处理完全取决于 Error 的类型和所调用的 API 风格。

所有 JavaScript 错误都作为异常处理,使用标准 JavaScript throw 机制 立即 生成并抛出错误。这些错误使用 JavaScript 语言提供的 try…catch 结构 来处理。

// 因为 z 未定义而抛出 ReferenceError。
try {
  const m = 1;
  const n = m + z;
} catch (err) {
  // 在此处处理错误。
}

任何使用 JavaScript throw 机制的行为都会引发一个 必须 被处理的异常,否则 Node.js 进程将立即退出。

除了少数例外,同步 API(任何不返回 <Promise> 也不接受 callback 函数的阻塞方法,例如 fs.readFileSync),将使用 throw 来报告错误。

异步 API 中发生的错误可以通过多种方式报告:

  • 某些异步方法返回一个 <Promise>,你应该始终考虑到它可能会被拒绝。请参阅 --unhandled-rejections 标志以了解进程将如何反应未处理的 promise 拒绝。

    const fs = require('node:fs/promises');
    
    (async () => {
      let data;
      try {
        data = await fs.readFile('a file that does not exist');
      } catch (err) {
        console.error('读取文件时出错!', err);
        return;
      }
      // 否则处理数据
    })();
  • 大多数接受 callback 函数的异步方法将接受一个作为该函数第一个参数传递的 Error 对象。如果第一个参数不是 null 且是 Error 的实例,则发生了应该处理的错误。

    const fs = require('node:fs');
    fs.readFile('a file that does not exist', (err, data) => {
      if (err) {
        console.error('读取文件时出错!', err);
        return;
      }
      // 否则处理数据
    });
  • 当在 EventEmitter 对象上调用异步方法时,错误可以被路由到该对象的 'error' 事件。

    const net = require('node:net');
    const connection = net.connect('localhost');
    
    // 向流添加 'error' 事件处理程序:
    connection.on('error', (err) => {
      // 如果连接被服务器重置,或者根本无法
      // 连接,或者连接遇到任何类型的错误,
      // 错误将被发送到这里。
      console.error(err);
    });
    
    connection.pipe(process.stdout);
  • Node.js API 中少数通常为异步的方法可能仍然使用 throw 机制来抛出必须使用 try…catch 处理的异常。没有此类方法的综合列表;请参阅每个方法的文档以确定所需的适当错误处理机制。

'error' 事件机制的使用对于 基于流的基于事件发射器的 API 最为常见,它们本身代表了一系列随时间进行的异步操作(而不是单个可能成功或失败的操作)。

对于 所有 EventEmitter 对象,如果没有提供 'error' 事件处理程序,错误将被抛出,导致 Node.js 进程报告未捕获异常并崩溃,除非:已为 'uncaughtException' 事件注册了处理程序,或使用了已弃用的 [node:domain][domains] 模块。

const EventEmitter = require('node:events');
const ee = new EventEmitter();

setImmediate(() => {
  // 这将导致进程崩溃,因为没有添加
  // 'error' 事件处理程序。
  ee.emit('error', new Error('这会导致崩溃'));
});

以这种方式生成的错误 不能 使用 try…catch 拦截,因为它们是在调用代码已经退出 之后 抛出的。

开发者必须参考每个方法的文档以确定这些方法抛出的错误究竟是如何传播的。

一个通用的 JavaScript <Error> 对象,不表示错误发生的任何具体情况。Error 对象捕获“堆栈跟踪”,详细说明 Error 实例化的代码点,并可能提供错误的文本描述。

Node.js 生成的所有错误,包括所有系统和 JavaScript 错误,要么是 Error 类的实例,要么继承自该类。

创建一个新的 Error 对象并将 error.message 属性设置为提供的文本消息。如果将对象作为 message 传递,则通过调用 String(message) 生成文本消息。如果提供了 cause 选项,则将其分配给 error.cause 属性。error.stack 属性将表示调用 new Error() 的代码点。堆栈跟踪依赖于 V8 的堆栈跟踪 API。堆栈跟踪仅扩展到 (a) 同步代码执行 的开始,或 (b) 属性 Error.stackTraceLimit 给出的帧数,以较小者为准。

targetObject 上创建一个 .stack 属性,访问该属性时返回一个字符串,表示调用 Error.captureStackTrace() 的代码位置。

const myObject = {};
Error.captureStackTrace(myObject);
myObject.stack;  // 类似于 `new Error().stack`

跟踪的第一行将以前缀 ${myObject.name}: ${myObject.message} 开头。

可选的 constructorOpt 参数接受一个函数。如果给定,则生成的堆栈跟踪中将省略 constructorOpt 及以上的所有帧,包括 constructorOpt

constructorOpt 参数有助于向用户隐藏错误生成的实现细节。例如:

function a() {
  b();
}

function b() {
  c();
}

function c() {
  // 创建一个没有堆栈跟踪的错误,以避免计算堆栈跟踪两次。
  const { stackTraceLimit } = Error;
  Error.stackTraceLimit = 0;
  const error = new Error();
  Error.stackTraceLimit = stackTraceLimit;

  // 捕获函数 b 以上的堆栈跟踪
  Error.captureStackTrace(error, b); // 堆栈跟踪中既不包含函数 c,也不包含 b
  throw error;
}

a();

Error.stackTraceLimit 属性指定堆栈跟踪收集的堆栈帧数(无论是通过 new Error().stack 还是 Error.captureStackTrace(obj) 生成)。

默认值为 10,但可以设置为任何有效的 JavaScript 数字。更改将影响在值更改 之后 捕获的任何堆栈跟踪。

如果设置为非数字值,或设置为负数,堆栈跟踪将不捕获任何帧。

如果存在,error.cause 属性是 Error 的根本原因。它用于捕获错误并抛出具有不同消息或代码的新错误,以便仍然可以访问原始错误。

error.cause 属性通常通过调用 new Error(message, { cause }) 设置。如果未提供 cause 选项,则构造函数不会设置它。

此属性允许错误链接。当序列化 Error 对象时,如果设置了 util.inspect(),则会递归序列化 error.cause

const cause = new Error('远程 HTTP 服务器响应了 500 状态');
const symptom = new Error('消息发送失败', { cause });

console.log(symptom);
// 打印:
//   Error: 消息发送失败
//       at REPL2:1:17
//       at Script.runInThisContext (node:vm:130:12)
//       ... 7 行匹配 cause 堆栈跟踪 ...
//       at [_line] [as _line] (node:internal/readline/interface:886:18) {
//     [cause]: Error: 远程 HTTP 服务器响应了 500 状态
//         at REPL1:1:15
//         at Script.runInThisContext (node:vm:130:12)
//         at REPLServer.defaultEval (node:repl:574:29)
//         at bound (node:domain:426:15)
//         at REPLServer.runBound [as eval] (node:domain:437:12)
//         at REPLServer.onLine (node:repl:902:10)
//         at REPLServer.emit (node:events:549:35)
//         at REPLServer.emit (node:domain:482:12)
//         at [_onLine] [as _onLine] (node:internal/readline/interface:425:12)
//         at [_line] [as _line] (node:internal/readline/interface:886:18)

error.code 属性是一个字符串标签,用于识别错误的种类。error.code 是识别错误最稳定的方式。它只会在 Node.js 的主要版本之间更改。相比之下,error.message 字符串可能会在 Node.js 的任何版本之间更改。有关特定代码的详细信息,请参阅 Node.js 错误代码

error.message 属性是通过调用 new Error(message) 设置的错误的字符串描述。传递给构造函数的 message 也会出现在 Error 堆栈跟踪的第一行,但是在 Error 对象创建后更改此属性 可能不会 更改堆栈跟踪的第一行(例如,当在更改此属性之前读取 error.stack 时)。

const err = new Error('The message');
console.error(err.message);
// 打印:消息

error.stack 属性是一个字符串,描述 Error 实例化的代码点。

Error: 事情不断发生!
   at /home/gbusey/file.js:525:2
   at Frobnicator.refrobulate (/home/gbusey/business-logic.js:424:21)
   at Actor.<anonymous> (/home/gbusey/actors.js:400:8)
   at increaseSynergy (/home/gbusey/actors.js:701:6)

第一行格式为 <error class name>: <error message>,后跟一系列堆栈帧(每行以 "at " 开头)。

每个帧描述代码中导致错误生成的调用站点。V8 尝试为每个函数显示一个名称(通过变量名、函数名或对象方法名),但偶尔无法找到合适的名称。如果 V8 无法确定函数的名称,则该帧仅显示位置信息。否则,将显示确定的函数名称,并在括号中附加位置信息。

帧仅为 JavaScript 函数生成。例如,如果执行同步通过一个名为 cheetahify 的 C++ 插件函数,该函数本身调用一个 JavaScript 函数,则代表 cheetahify 调用的帧将不会出现在堆栈跟踪中:

const cheetahify = require('./native-binding.node');

function makeFaster() {
  // `cheetahify()` *同步* 调用 speedy。
  cheetahify(function speedy() {
    throw new Error('oh no!');
  });
}

makeFaster();
// 将抛出:
//   /home/gbusey/file.js:6
//       throw new Error('oh no!');
//           ^
//   Error: 哦不!
//       at speedy (/home/gbusey/file.js:6:11)
//       at makeFaster (/home/gbusey/file.js:5:3)
//       at Object.<anonymous> (/home/gbusey/file.js:10:1)
//       at Module._compile (module.js:456:26)
//       at Object.Module._extensions..js (module.js:474:10)
//       at Module.load (module.js:356:32)
//       at Function.Module._load (module.js:312:12)
//       at Function.Module.runMain (module.js:497:10)
//       at startup (node.js:119:16)
//       at node.js:906:3

位置信息将是以下之一:

  • native,如果帧表示 V8 内部的调用(如 [].forEach)。
  • plain-filename.js:line:column,如果帧表示 Node.js 内部的调用。
  • /absolute/path/to/file.js:line:column,如果帧表示用户程序中的调用(使用 CommonJS 模块系统),或其依赖项。
  • <transport-protocol>:///url/to/module/file.mjs:line:column,如果帧表示用户程序中的调用(使用 ES 模块系统),或其依赖项。

堆栈跟踪捕获的帧数受 Error.stackTraceLimit 或当前事件循环滴答可用帧数中较小者的限制。

error.stack 是隐藏内部属性的 getter/setter,仅存在于内置 Error 对象上(那些 Error.isError 返回 true 的对象)。如果 error 不是内置错误对象,则 error.stack getter 将始终返回 undefined,setter 将不执行任何操作。如果访问器是使用非内置错误对象的 this 值手动调用的,例如 <Proxy>,则可能发生这种情况。

表示断言失败。详细信息,请参阅 [ 类:assert.AssertionError][]】【。

表示提供的参数不在函数的可接受值集或范围内; 无论是数值范围,还是超出给定函数参数的选项集。

require('node:net').connect(-1);
// 抛出 "RangeError: "port" 选项应 >= 0 且 < 65536: -1"

Node.js 会 立即 生成并抛出 RangeError 实例,作为一种参数验证形式。

表示试图访问未定义的变量。此类错误通常表明代码中有拼写错误, 或者程序已损坏。

虽然客户端代码可以生成并传播这些错误,但实际上,只有 V8 会这样做。

doesNotExist;
// 抛出 ReferenceError,doesNotExist 在此程序中不是变量。

除非应用程序动态生成并运行代码, 否则 ReferenceError 实例表明代码或其依赖项中存在错误。

表示程序不是有效的 JavaScript。这些错误只能 作为代码求值的结果生成和传播。代码求值可能 作为 evalFunctionrequirevm 的结果发生。这些错误 几乎总是表明程序已损坏。

try {
  require('node:vm').runInThisContext('binary ! isNotOk');
} catch (err) {
  // 'err' 将是一个 SyntaxError。
}

SyntaxError 实例在创建它们的上下文中是不可恢复的—— 它们只能被其他上下文捕获。

当 Node.js 运行时环境中发生异常时,会生成系统错误。这些通常发生在应用程序违反 操作系统约束时。例如,如果应用程序 尝试读取不存在的文件,将发生系统错误。

Attributes
address:<string>
如果存在,则为网络连接 失败的地址
字符串错误代码
如果存在,则为报告文件 系统错误时的文件路径目标
errno:<number>
系统提供的错误号
如果存在,则为关于错误条件的额外详细信息
message:<string>
系统提供的错误人类可读描述
如果存在,则为报告文件系统错误时的文件路径
如果存在,则为不可用的网络连接端口
syscall:<string>
触发错误的系统调用名称

如果存在,error.address 是一个字符串,描述网络连接 失败的地址。

error.code 属性是一个表示错误代码的字符串。

如果存在,error.dest 是报告文件 系统错误时的文件路径目标。

error.errno 属性是一个负数,对应 于 [libuv 错误处理][] 中定义的错误代码。

在 Windows 上,系统提供的错误号将由 libuv 规范化。

要获取错误代码的字符串表示形式,请使用 util.getSystemErrorName(error.errno)

如果存在,error.info 是一个包含有关错误条件详细信息的对象。

error.message 是系统提供的错误人类可读描述。

如果存在,error.path 是一个包含相关无效路径名的字符串。

如果存在,error.port 是不可用的网络连接端口。

error.syscall 属性是一个描述失败的 [syscall][] 的字符串。

  • EACCES(权限被拒绝):试图以文件访问权限 禁止的方式访问文件。

  • EADDRINUSE(地址已被使用):试图将服务器 (nethttphttps)绑定到本地地址失败,因为 本地系统上的另一个服务器已占用该地址。

  • ECONNREFUSED(连接被拒绝):无法建立连接,因为 目标机器主动拒绝了它。这通常是由于试图 连接到外部主机上未活动的服务。

  • ECONNRESET(连接被对方重置):连接被 对方强制关闭。这通常是由于超时或重启导致远程 套接字上的连接丢失。通常通过 httpnet 模块遇到。

  • EEXIST(文件存在):现有文件是要求目标 不存在的操作的目标。

  • EISDIR(是一个目录):操作期望一个文件,但给定的 路径名是一个目录。

  • EMFILE(系统中打开的文件太多):系统允许的 文件描述符 最大数量已达到, 在至少关闭一个之前,无法满足另一个描述符的 请求。这在同时打开许多文件时会遇到, 特别是在进程文件描述符限制较低的系统(特别是 macOS)上。要补救低限制,请在运行 Node.js 进程的同一 shell 中运行 ulimit -n 2048

  • ENOENT(没有这样的文件或目录):通常由 fs 操作 抛出,表示指定路径名的组件不存在。给定路径找不到 任何实体(文件或目录)。

  • ENOTDIR(不是目录):给定路径名的组件存在,但 不是预期的目录。通常由 fs.readdir 抛出。

  • ENOTEMPTY(目录不为空):具有条目的目录是 要求空目录的操作的目标,通常是 fs.unlink

  • ENOTFOUND(DNS 查找失败):表示 EAI_NODATAEAI_NONAME 的 DNS 失败。这不是标准的 POSIX 错误。

  • EPERM(操作不允许):试图执行需要 提升权限的操作。

  • EPIPE(管道破裂):在没有进程 读取数据的情况下写入管道、套接字或 FIFO。通常在 nethttp 层遇到,表明正在 写入的流的远程端已关闭。

  • ETIMEDOUT(操作超时):连接或发送请求失败,因为 连接方在一段时间后未正确响应。通常 由 httpnet 遇到。通常是 socket.end() 未正确调用的标志。

表示提供的参数不是允许的类型。例如, 向一个期望字符串的参数传入函数会导致 TypeError

require('node:url').parse(() => { });
// 抛出 TypeError,因为它期望的是一个字符串。

Node.js 会作为参数校验的一种形式,立即 生成并抛出 TypeError 实例。

JavaScript 异常是作为无效操作的结果或作为 throw 语句的目标而抛出的值。虽然不要求 这些值是 Error 的实例或继承自 Error 的类,但由 Node.js 或 JavaScript 运行时抛出的所有异常 Error 的实例。

某些异常在 JavaScript 层是 不可恢复的。此类异常 始终 会导致 Node.js 进程崩溃。示例包括 C++ 层中的 assert() 检查或 abort() 调用。

源自 cryptotls 的错误属于 Error 类,除了 标准的 .code.message 属性外,可能还有一些额外的 OpenSSL 特定属性。

不使用 AbortSignal 的 API 通常不会抛出带有此代码的错误。

为了与 Web 平台的 AbortError 兼容,此代码不使用 Node.js 错误所采用的常规 ERR_* 约定。

遇到此错误时,创建 Buffer 实例的可能替代方案是创建普通的 Uint8Array,它仅在 结果对象的原型上有所不同。Uint8Array 通常在所有 使用 Buffer 的 Node.js 核心 API 中都被接受;它们在所有上下文中都可用。

堆栈跟踪被扩展以包括 node:domain 模块被加载的时间点。

抛出的错误对象包括一个 input 属性,其中包含无效 file: URL 的 URL 对象。

const urlSearchParams = new URLSearchParams('foo=bar&baz=new');

const buf = Buffer.alloc(1);
urlSearchParams.has.call(buf, 'foo');
// 抛出代码为 'ERR_INVALID_THIS' 的 TypeError

A callback should almost always be called only once, because a query can be fulfilled or rejected, but not both. The latter can be achieved by calling the callback multiple times.

$ node --experimental-package-map=./package-map.json /tmp/script.js
Error [ERR_PACKAGE_MAP_EXTERNAL_FILE]: Cannot resolve "dep-a" from "/tmp/script.js": file is not within any package defined in /path/to/package-map.json

要修复此错误,请确保导入文件位于包映射中列出的某个包目录内,或者添加一个新的包条目,使其 url 覆盖导入文件。

  • 文件在指定路径下不存在。
  • 文件包含无效的 JSON。
  • 文件缺少必需的 packages 对象。
  • 某个包条目缺少必需的 url 字段。
  • 两个包条目具有相同的 url 值。
$ node --experimental-package-map=./missing.json app.js
Error [ERR_PACKAGE_MAP_INVALID]: 无效的 package map 位于 "./missing.json":未找到文件

{
  "packages": {
    "app": {
      "url": "./app",
      "dependencies": {
        "foo": "nonexistent"
      }
    }
  }
}

In this example, "nonexistent" is referenced as a dependency target, but it is not defined in packages, which will throw this error.

To fix this error, make sure that all package keys referenced in dependencies values are defined in the packages object.

发生 QUIC 应用程序错误。

建立 QUIC 连接失败。

QUIC 端点因错误而关闭。

打开 QUIC 流失败。

用于抛出 QuicError 的 Node.js 错误代码,以使用显式应用程序或传输错误代码中止 QUIC 流 或会话。

QUIC 流被对端重置。错误包含 对端提供的重置代码。

发生 QUIC 传输错误。

QUIC 会话失败,因为需要进行版本协商。

在未被捕获时,标志 --experimental-print-required-tla 会将 图中顶层 await 的位置打印到 stderr。

此错误具有以下额外的不可枚举属性:

Attributes
requireStack:<string>
[] 导致失败的  require() 的模块链,从要求异步模块的模块开始。
topLevelAwaitLocations:<Object>
[] 图中顶层 await 的位置。仅在启用  --experimental-print-required-tla 时填充。 每个条目具有以下属性:
包含顶层 await 的模块的 URL。
顶层 await 所在的行号,基于 1。
column:<number>
顶层 await 所在的列号,基于 1。
sourceLine:<string>
包含顶层 await 的源码行。

尝试 require() ES 模块。此错误已弃用,因为 require() 现在支持加载同步 ES 模块。当 require() 遇到包含顶层 await 的 ES 模块时,将改为抛出 ERR_REQUIRE_ASYNC_MODULE

当另一个 import() 调用已经在异步加载它时,尝试 require() 一个 ES 模块

const Socket = require('node:net').Socket;
const instance = new Socket();

instance.setEncoding('utf8');

此错误旨在防止意外覆盖由另一个模块注册的回调。

import './'; // 不支持
import './index.js'; // 支持
import 'package-name'; // 支持

try {
  // 尝试从 `data:` URL 模块导入包 'bare-specifier':
  await import('data:text/javascript,import "bare-specifier"');
} catch (e) {
  console.log(e.code); // ERR_UNSUPPORTED_RESOLVE_REQUEST
}

  • 它已经被链接过(linkingStatus'linked'
  • 它正在链接过程中(linkingStatus'linking'
  • 链接该模块失败(linkingStatus'errored'

目标线程在处理通过 postMessageToThread() 发送的消息时抛出错误。

postMessageToThread() 中请求的线程无效或没有 workerMessage 监听器。

postMessageToThread() 中请求的线程 ID 是当前线程 ID。

通过 postMessageToThread() 发送消息超时。

Transfer-Encoding: chunked 允许服务器为动态生成的内容维护 HTTP 持久连接。在这种情况下,不能使用 Content-Length HTTP 头。

使用 Content-LengthTransfer-Encoding: chunked

稳定性:0 - 已弃用。这些错误代码要么不一致,要么已被移除。

在 v15.0.0 之前的 Node.js 版本中,此处使用的错误代码是 ERR_MISSING_MESSAGE_PORT_IN_TRANSFER_LIST。但是,可传输对象类型的集合已扩展,涵盖比 MessagePort 更多的类型。

这只有在原生插件以“外部化”模式创建 SharedArrayBuffer,或将现有 SharedArrayBuffer 放入外部化模式时才会发生。

证书尚未生效:notBefore 日期在当前时间之后。

证书已过期:notAfter 日期在当前时间之前。

证书吊销列表 (CRL) 具有未来的签发日期。

证书吊销列表 (CRL) 已过期。

证书已被吊销;它位于证书吊销列表 (CRL) 上。

找不到查找证书的颁发者证书。这通常意味着受信任证书列表不完整。

证书的颁发者未知。如果颁发者未包含在受信任证书列表中,就会出现这种情况。

传入的证书是自签名的,并且在受信任证书列表中找不到相同的证书。

证书的颁发者未知。如果颁发者未包含在受信任证书列表中,就会出现这种情况。

证书链长度大于最大深度。

找不到证书引用的 CRL。

无法验证任何签名,因为链只包含一个证书且它不是自签名的。

根证书颁发机构 (CA) 未标记为用于指定目的的可信机构。

CA 证书无效。要么它不是 CA,要么其扩展与提供的目的不一致。

basicConstraints pathlength 参数已超出。

证书与提供的名称不匹配。

提供的证书不能用于指定目的。

根 CA 被标记为拒绝指定目的。

证书签名无效。

证书吊销列表 (CRL) 的签名无效。

证书 notBefore 字段包含无效时间。

证书 notAfter 字段包含无效时间。

CRL lastUpdate 字段包含无效时间。

CRL nextUpdate 字段包含无效时间。

证书签名无法解密。这意味着无法确定实际签名值,而不是它与预期值不匹配,这仅对 RSA 密钥有意义。

证书吊销列表 (CRL) 签名无法解密:这意味着无法确定实际签名值,而不是它与预期值不匹配。

无法读取证书 SubjectPublicKeyInfo 中的公钥。

尝试分配内存时发生错误。这绝不应该发生。