You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Joi配合react-hook-form校验上传图片时触发读取length属性报错

react-hook-form 搭配 Joi 校验上传图片报错解决方案

报错根因

你遇到的Cannot read properties of undefined (reading 'length')错误,核心是错误使用Joi.object()嵌套规则校验浏览器原生File实例:

  • 你当前写的avatar: Joi.object({type: xxx, size: xxx})规则,默认要求传入值是普通JS对象(plain object),但实际上传拿到的avatar是浏览器原生的File实例,不属于普通对象范畴。
  • Joi执行内置object规则校验时,会递归遍历对象的所有内部属性做匹配,而File实例的部分内部属性是不可枚举、访问受保护的,当Joi尝试读取这类属性的length值做校验时,就会拿到undefined触发类型错误。
  • 当你把规则改成空的Joi.object().unknown(true)时,Joi不会深入递归校验内部属性,仅判断值为对象类型就放行,所以不会触发报错,但也无法实现格式、大小的校验逻辑。

修复方案

不要用嵌套object规则校验File/Blob这类宿主对象,改用Joi.custom()自定义校验逻辑,直接读取File实例的公开属性做判断即可:

export type AvatarForm = {
    avatar: File;
};

// 限制图片最大2MB
const MAX_AVATAR_SIZE = 2 * 1024 * 1024;
const ALLOWED_IMAGE_TYPES = ["image/png", "image/jpeg"];

export const AvatarSchema = Joi.object<AvatarForm, true>({
    avatar: Joi.custom((value, helpers) => {
        // 校验是否为有效File实例
        if (!(value instanceof File)) {
            return helpers.error("file.invalid", { message: "请上传有效图片文件" });
        }
        // 校验文件格式
        if (!ALLOWED_IMAGE_TYPES.includes(value.type)) {
            return helpers.error("file.type", { message: "仅支持PNG、JPEG格式的图片" });
        }
        // 校验文件大小
        if (value.size > MAX_AVATAR_SIZE) {
            return helpers.error("file.size", { message: "图片大小不能超过2MB" });
        }
        return value;
    }).required()
});

额外排查点

  • 检查size字段的规则类型匹配:File.size是数字类型,如果误写了Joi.string().length()这类字符串专属的校验规则,Joi尝试读取数字值的length属性时也会触发同类报错。
  • 确认表单绑定逻辑正确:检查上传组件是否正确将File实例赋值给avatar字段,如果字段值为null/undefined,Joi读取空值属性时也会抛错,可通过.required()明确字段必填要求。
  • 版本兼容校验:如果使用的是7.0以下版本的@hookform/resolvers/joi,建议升级到最新版本,旧版本resolver在传递File这类特殊对象给Joi时存在序列化bug,会丢失对象属性触发校验异常。

内容的提问来源于stack exchange,提问作者matikowy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 06:24:16