Repository navigation
Errors
sungaowei edited this page Oct 16, 2026
·
2 revisions
English Version | 简体中文
SDK 返回的所有错误均实现了 typesafe.TypeSafeError 接口。
所有非 2xx 的 HTTP 失败状态码都会映射为具体的强类型错误结构体,并且每个类型化错误均嵌套了 *APIError(并支持 Unwrap() 解包),因此你可以使用标准库 errors.As 既匹配特定子类型,也匹配通用的 *APIError。
| 状态码 | 错误类型 | 说明 |
|---|---|---|
| 400 | *BadRequestError |
请求参数有误或 JSON 格式非法 |
| 401 | *AuthenticationError |
API Key 缺失、无效或已过期 |
| 403 | *PermissionDeniedError |
账号权限不足,例如未开通相关模型 |
| 404 | *NotFoundError |
请求的端点或资源不存在 |
| 413 | *PayloadTooLargeError |
请求体超过 32 MiB 限制,或单张图片超过 16 MiB 上限 |
| 415 | *UnsupportedMediaTypeError |
请求的 Content-Type 不受支持,或图片格式非法(仅支持 PNG/JPEG) |
| 422 | *UnprocessableEntityError |
业务语义校验失败(如字段值不合法) |
| 429 | *RateLimitError |
触发接口限流,附带 RetryAfter() (time.Duration, bool)
|
| 529 | *OverloadedError |
服务端处于过载保护中,附带 RetryAfter()
|
| 5xx | *InternalServerError |
服务端内部异常 |
| 其他非 2xx | *APIError |
其他未显式列出的非正常 HTTP 响应 |
| 错误类型 | 触发原因 |
|---|---|
*SDKError |
本地配置非法、非法输入参数、无法序列化的请求体,绝不是网络对端返回的状态码。 |
*APIConnectionError |
网络握手失败、DNS 解析失败或 TCP 提前断开,从未收到 HTTP 响应。 |
*APITimeoutError |
请求超出配置的超时上限,包含 Timeout time.Duration。 |
*APIResponseValidationError |
服务端返回了 2xx 成功状态码,但响应体格式不符合预期,包含出错字段路径 FieldPath。 |
*ScoreError |
构建 Score 问题时评分阶梯少于 2 级或为空。 |
所有 HTTP 错误底层嵌套的 *APIError 均携带了详尽的网络上下文:
type APIError struct {
Status int // HTTP 响应状态码(如 400, 429, 500 等)
Body any // 解析后的 JSON 错误对象、纯文本内容或 nil
RawBody []byte // 服务端返回的原始未经修改的二进制字节
Headers http.Header // 完整的响应标头
Endpoint string // 脱敏后的 "METHOD URL"(剔除了密码、Query 和 Hash)
RequestID string // 服务端响应标头 x-typesafe-request-id,便于工单排查
Message string // 从响应体中智能提取的人类可读错误详情
}其 Error() 方法格式化为:<METHOD URL>: <status> <message> (request_id=<id>),会自动省略不适用的空字段。
response, err := client.SystemOne(ctx, state, questions)
if err != nil {
var rateLimit *typesafe.RateLimitError
var payloadTooLarge *typesafe.PayloadTooLargeError
var validation *typesafe.APIResponseValidationError
var timeout *typesafe.APITimeoutError
var apiErr *typesafe.APIError
switch {
case errors.As(err, &rateLimit):
if wait, ok := rateLimit.RetryAfter(); ok {
log.Printf("触发限频,建议等待 %v 后重试", wait)
}
case errors.As(err, &payloadTooLarge):
log.Printf("请求体过大 (超过 32 MiB 或图片超过 16 MiB): %v", payloadTooLarge)
case errors.As(err, &validation):
log.Printf("响应数据字段校验失败: %q", validation.FieldPath)
case errors.As(err, &timeout):
log.Printf("请求超时 (单次上限: %v)", timeout.Timeout)
case errors.As(err, &apiErr):
log.Printf("HTTP %d (请求 ID: %s): %s", apiErr.Status, apiErr.RequestID, apiErr.Message)
default:
log.Printf("调用失败: %v", err)
}
return err
}匹配原则:优先匹配最具体的类型(如
*RateLimitError、*PayloadTooLargeError),最后再回退到*APIError。
SDK 提供了一组开箱即用的类型提取函数,均遵循 Go 惯用的 (value, bool) 签名:
| 辅助函数 | 匹配目标 |
|---|---|
typesafe.AsAPIError(err) |
任意非 2xx HTTP 失败 |
typesafe.AsRateLimitError(err) |
HTTP 429,或兼容的 HTTP 529 |
typesafe.AsOverloadedError(err) |
HTTP 529 服务端过载 |
typesafe.AsPayloadTooLargeError(err) |
HTTP 413 负载过大 |
typesafe.AsUnsupportedMediaTypeError(err) |
HTTP 415 不支持的媒体类型 |
typesafe.AsTimeoutError(err) |
请求超时 |
typesafe.AsValidationError(err) |
成功状态码但解析失败的响应 |
if ptlErr, ok := typesafe.AsPayloadTooLargeError(err); ok {
log.Printf("413 错误: %s", ptlErr.Message)
}SDK 会自动根据主流 API 规范与反向代理格式,从响应体中提取最核心的 Message 说明文本:
| 响应体格式 | 提取出的 Message |
|---|---|
{"error": "..."} |
对应字符串 |
{"error": {"message": "..."}} |
嵌套字典中的 message |
{"message": "..."} |
对应字符串 |
{"detail": "..."} |
对应字符串 |
{"detail": {"message": "..."}} |
嵌套字典中的 message |
{"detail": [{"loc": [...], "msg": "..."}]} |
多段错误拼接为 path: msg; ...,并剔除前导 body.
|
| 单独的 JSON 裸字符串 | 对应字符串 |
| 其他非结构化内容 | 截取前 200 个字节并附加 … 省略号 |
- 指南
- Guides