Mongoose中Error.ValidationError与Error.ValidatorError的区别
ValidationError与ValidatorError的差异说明 你的推测存在部分偏差,二者是明确的层级包含关系,不存在平级触发的可能,具体规则如下:
核心定位与触发场景
mongoose.Error.ValidationError
这是Mongoose验证流程抛出的顶层文档级错误,所有验证场景失败后,业务代码catch到的最外层错误都是该类实例。触发场景覆盖所有Schema定义的校验规则不通过的情况:包括必填字段缺失、字段值超出maxLength/min/max阈值、类型不匹配、enum值不在允许列表、自定义校验规则不通过等。
该实例的核心属性是errors,为键值对结构:key是校验失败的字段路径,value是对应字段的具体错误对象。mongoose.Error.ValidatorError
这是单条校验规则维度的底层错误,永远不会作为顶层错误单独抛出,所有单字段单规则校验失败生成的错误实例都是该类,它会作为属性值挂载在上面提到的ValidationError.errors对应字段的键下。
注意:不止自定义校验器失败会生成该类错误,内置校验规则(required、maxLength、enum等)校验失败时,同样会生成ValidatorError实例。
容易混淆的reason字段说明
你之前提到的「作为reason属性存在的错误」,并不是ValidatorError本身:当自定义校验器函数内部主动抛出了原生Error对象(而非返回false表示校验失败)时,这个自定义逻辑里抛出的原始错误,会被挂载到对应ValidatorError实例的reason属性上,方便开发者排查自定义校验逻辑的内部问题。
实际运行示例
const userSchema = new Schema({ username: { type: String, required: true, maxlength: 8 }, age: { type: Number, validate: { validator: (val) => { if (val < 0) throw new Error('年龄参数非法,不能为负数') return val >= 18 }, message: '用户年龄需满18周岁' } } }) const User = mongoose.model('User', userSchema) // 构造不符合校验规则的文档 const invalidUser = new User({ username: '过长的用户名超过长度限制', age: -5 }) try { await invalidUser.validate() } catch (err) { // 最外层捕获的是ValidationError console.log(err instanceof mongoose.Error.ValidationError) // 输出true // 字段对应的单条错误是ValidatorError实例 console.log(err.errors.username instanceof mongoose.Error.ValidatorError) // 输出true console.log(err.errors.age instanceof mongoose.Error.ValidatorError) // 输出true // 自定义校验器内部抛出的原始错误挂在reason属性上 console.log(err.errors.age.reason.message) // 输出"年龄参数非法,不能为负数" }
快速排查提示:实际业务中只需要在外层捕获
ValidationError即可,无需单独监听ValidatorError;要定位具体失败字段和原因,遍历ValidationError.errors对象读取对应ValidatorError的信息即可。
内容的提问来源于stack exchange,提问作者Jack_Hu

