TOAST_ERROR_FIX.md 4.2 KB

Toast 错误对象渲染问题修复

问题描述

在保存标注结果时出现错误:

Objects are not valid as a React child (found: object with keys {type, loc, msg, input, url})

问题原因

FastAPI 的验证错误返回的是一个对象数组,每个对象包含:

  • type: 错误类型
  • loc: 错误位置(字段路径)
  • msg: 错误消息
  • input: 输入值
  • url: 文档链接

当这个对象直接传递给 Toast 组件时,React 无法渲染对象,导致错误。

解决方案

1. 增强 API 拦截器错误处理

web/apps/lq_label/src/services/api.ts 中:

apiClient.interceptors.response.use(
  (response) => response,
  (error: AxiosError) => {
    let errorMessage = '发生了意外错误';
    
    if (error.response?.data) {
      const data = error.response.data as any;
      
      // Handle FastAPI validation errors (array of error objects)
      if (Array.isArray(data.detail)) {
        // Format validation errors into readable message
        errorMessage = data.detail
          .map((err: any) => {
            const field = err.loc?.join('.') || '字段';
            return `${field}: ${err.msg}`;
          })
          .join('; ');
      } 
      // Handle simple string error message
      else if (typeof data.detail === 'string') {
        errorMessage = data.detail;
      }
      // Handle object error message
      else if (typeof data.detail === 'object' && data.detail !== null) {
        errorMessage = JSON.stringify(data.detail);
      }
      // Fallback to error message
      else if (data.message) {
        errorMessage = data.message;
      }
    } else if (error.message) {
      errorMessage = error.message;
    }

    toast.error(errorMessage);
    // ...
  }
);

改进点

  • ✅ 检测 FastAPI 验证错误数组
  • ✅ 格式化为可读的字符串(字段: 错误消息
  • ✅ 处理多种错误格式(字符串、对象、数组)
  • ✅ 提供详细的调试日志

2. 增强 Toast 服务的类型安全

web/apps/lq_label/src/services/toast.ts 中:

error(message: string | any, title?: string, duration = 5000): void {
  // 确保 message 是字符串
  let messageStr: string;
  if (typeof message === 'string') {
    messageStr = message;
  } else if (message && typeof message === 'object') {
    // 如果是对象,尝试提取有用信息
    if (message.message) {
      messageStr = message.message;
    } else if (message.msg) {
      messageStr = message.msg;
    } else {
      messageStr = JSON.stringify(message);
    }
  } else {
    messageStr = String(message);
  }

  this.notify({
    type: ToastType.error,
    title: title || '错误',
    message: messageStr,
    duration,
  });
}

改进点

  • ✅ 接受任意类型的 message 参数
  • ✅ 自动转换对象为字符串
  • ✅ 尝试提取对象中的 messagemsg 字段
  • ✅ 最后兜底使用 JSON.stringify()String()

错误格式示例

FastAPI 验证错误格式

{
  "detail": [
    {
      "type": "string_type",
      "loc": ["body", "name"],
      "msg": "Input should be a valid string",
      "input": null,
      "url": "https://errors.pydantic.dev/..."
    },
    {
      "type": "missing",
      "loc": ["body", "data"],
      "msg": "Field required",
      "input": {"name": "test"},
      "url": "https://errors.pydantic.dev/..."
    }
  ]
}

格式化后的错误消息

body.name: Input should be a valid string; body.data: Field required

测试场景

修复后,以下场景都能正确显示错误消息:

  1. ✅ FastAPI 验证错误(对象数组)
  2. ✅ 简单字符串错误
  3. ✅ 对象错误
  4. ✅ 网络错误
  5. ✅ 超时错误

相关文件

  • web/apps/lq_label/src/services/api.ts - API 拦截器
  • web/apps/lq_label/src/services/toast.ts - Toast 服务

验证方法

  1. 尝试提交空的表单字段
  2. 尝试提交无效的 JSON 数据
  3. 尝试在网络断开时保存数据
  4. 检查 Toast 是否显示可读的错误消息

总结

通过增强错误处理逻辑,现在系统能够:

  • ✅ 正确处理 FastAPI 的验证错误
  • ✅ 将错误对象转换为可读的字符串
  • ✅ 在 Toast 中显示友好的错误消息
  • ✅ 避免 React 渲染对象的错误