---
url: /docs/api/validation-errors.md
---
# 输入校验与错误处理

## 输入校验

接口在 `.input()` 中使用 Zod，明确字符串长度、枚举、数量和格式。对外部文件和网址，还需要在处理阶段验证真实内容、响应大小和可访问范围；仅校验后缀或网址格式不够。

```ts
import { z } from "zod";

const listInput = z.object({
  limit: z.number().int().min(1).max(100).default(20),
});
```

## 统一错误

`apps/api/lib/trpc.ts` 为校验错误附加 `data.zodError`，客户端可把字段错误放回表单。业务错误使用 `TRPCError`，选择与实际情况一致的类型。

| 错误类型                | 场景                   |
| ----------------------- | ---------------------- |
| `BAD_REQUEST`           | 输入或请求状态不合法   |
| `UNAUTHORIZED`          | 缺少有效会话           |
| `FORBIDDEN`             | 已登录但无操作权限     |
| `NOT_FOUND`             | 资源不存在或不可见     |
| `CONFLICT`              | 唯一约束或当前状态冲突 |
| `INTERNAL_SERVER_ERROR` | 未预期的内部失败       |

```ts
import { TRPCError } from "@trpc/server";

throw new TRPCError({
  code: "FORBIDDEN",
  message: "当前账号没有管理权限",
});
```

示例说明错误表达方式；客户站文案按产品语言配置。

## 前端处理

使用 `apps/app/lib/errors.ts` 提取状态和可展示消息，区分校验错误、权限错误与网络故障。401 可以引导重新登录；403 应解释权限不足；网络故障保留输入供用户重试。

不要把所有异常改成“没有登录”，也不要在支付失败后自动重试创建订阅。日志保留内部原因和请求标识，响应隐藏堆栈、数据库连接和密钥。

## 环境错误

启动时 `parseEnv()` 检查字段组合，诊断只报告错误字段名。先修复缺失变量再重启；不要为了绕过报错把半组凭据补成无效占位值。
