错误码必须定义在服务对应的 .proto 文件 enum ErrorReason 中,每个枚举值需用 (errors.code) = NNN 显式绑定 HTTP 状态码,且必须通过 errors.Xxx() 封装返回,禁止 runtime 拼凑或直接 errors.New;errors.Is() 可安全跨服务判断类型。

错误码必须定义在 .proto 文件的 enum ErrorReason 中
Kratos 不接受运行时拼凑的错误码,也不允许在 handler 里用 errors.New("xxx") 或 fmt.Errorf 返回业务错误。所有可被外部识别、需透传到客户端的错误,必须提前声明为 Protobuf 的 enum,且推荐命名为 ErrorReason(非强制但为社区惯例)。否则 errors.Is() 匹配、HTTP 状态码映射、Swagger 文档生成都会失效。
- 定义位置必须在服务对应的
.proto文件内,和service同级 - 每个枚举值需通过
(errors.code) = NNN显式绑定 HTTP 状态码,例如USER_NOT_FOUND = 0 [(errors.code) = 404]; - 未加
(errors.code)的枚举项默认走(errors.default_code) = 500,但不建议依赖默认值 - 生成代码后,会产出
errors.Is(err, helloworld.ErrUserNotFound)这类类型安全判断函数,而不是字符串匹配
errors.New 和 errors.WithMessage 只能用于内部错误包装
你写的业务逻辑里可以调用 errors.New 或 errors.WithMessage,但这些错误不能直接返回给 transport 层——它们只是中间态。最终必须用 errors.BadRequest、errors.NotFound 等 Kratos 提供的封装函数,把底层 error 转成对应 enum 的错误实例。
-
errors.BadRequest(helloworld.ErrContentMissing, "name is empty"):第一个参数是 proto 里定义的 enum 错误变量,第二个是附加描述 - 这样返回后,HTTP 层自动设
Status: 400,gRPC 层设Code: InvalidArgument,且 message 字段含你传的描述 - 如果直接 return
errors.New("xxx"),transport 会 fallback 到 500 + generic message,丢失语义和状态码控制 - 注意:这些封装函数不改变原始 error 的堆栈,调试时仍可追溯
HTTP 响应状态码由 (errors.code) 控制,不是靠中间件硬写
别在 HTTP middleware 里用 w.WriteHeader(404) 手动设状态码。Kratos 的 http.Server 在 write response 前会自动从 error 中提取 (errors.code) 并设置 status。手动覆盖会导致状态码与 error 枚举不一致,Swagger 文档错乱,前端无法按 code 分支处理。
- 验证方式:curl -v 调用接口,看响应头
Status是否与 proto 中(errors.code)一致 - 如果始终是 500,先检查 proto 是否漏了
(errors.code)注解,再确认返回 error 是否来自errors.Xxx()封装 - 自定义编码器(如 XML/FORM)不影响该机制,status 提取发生在编码前
- gRPC 客户端收到的
status.Code()会映射为标准 gRPC code(如404 → NotFound),无需额外转换
错误码跨服务调用时,errors.Is 比字符串判断更可靠
当 A 服务调用 B 服务,B 返回了 helloworld.ErrUserNotFound,A 侧不要用 strings.Contains(err.Error(), "not found") 判断——proto enum 是类型安全的,应该直接用 errors.Is(err, helloworld.ErrUserNotFound)。
- 这个判断不依赖 error message 文本,即使 B 服务升级改了提示语也不会断
- 底层基于
errors.As()提取 proto enum 值,性能开销极小 - 如果 B 服务用的是不同版本的 proto(比如字段序号变了),只要 enum name 和
(errors.code)不变,errors.Is依然有效 - 注意:必须确保 A 服务 import 的是 B 服务发布的同一份
.pb.go,否则 enum 类型不匹配
package helloworld; 对应的 enum 必须也在同一个 proto 文件里;拆到独立 errors.proto 虽然语法合法,但 Kratos 的代码生成器默认不扫描它,errors.Is 会失效。


















