错误处理

每个 service 方法都返回一个普通的 error。传输层失败(DNS、连接被拒绝、 超时)会以 fmt.Errorf 包装后返回;任何被 Z.AI API 自身拒绝的请求会以 *client.APIError 形式返回,其中带有结构化字段,你可以据此分支处理,而不必 解析消息字符串。

resp, err := c.Chat().Create(ctx, req)
if err != nil {
    var apiErr *client.APIError
    if errors.As(err, &apiErr) {
        fmt.Printf("[%d] %s\n", apiErr.Code, apiErr.UserMessage)

        switch apiErr.Category {
        case client.ErrorCategoryAuth:
            // bad/expired key — don't retry, tell the user
        case client.ErrorCategoryQuota:
            // out of balance/quota — don't retry, surface to the user
        case client.ErrorCategoryRateLimit:
            if apiErr.IsRetriable {
                // the client already retries this internally up to
                // Config.MaxRetries — you'll only see it here if retries
                // were exhausted or disabled (MaxRetries: -1)
            }
        }
        return
    }
    // transport-level failure — network, DNS, timeout
}

APIError 字段:

Field Meaning
HTTPStatus HTTP 状态码
Code Z.AI 的业务错误码(int)
Message API 返回的原始消息
Category 下列分类之一
UserMessage 预先写好的、更友好的描述
IsRetriable client 自身的重试逻辑是否将其视为瞬时错误
RequestID 用于支持/调试,当 API 返回时携带

辅助谓词:IsAuthError()IsRateLimitError()IsQuotaError()IsParameterError()IsServerError()——等价于直接检查 .Category,提供 它们是为了在调用处更易读。

开箱即用的重试行为

Client.doRequest(被每个 service 使用)已经对 429/5xx/网络错误进行重试, 支持指数退避、抖动以及 Retry-After,最多重试到 Config.MaxRetries (默认为 3;设为 -1 可禁用)。你通常不需要自己写重试循环—— APIError.IsRetriable 会告诉你某个到达你代码的错误是否已经耗尽了那些重试。

错误码参考

Code Constant Category Retriable
1000 ErrCodeAuthFailed Auth
1001 ErrCodeAuthNotFound Auth
1003 ErrCodeAuthTokenExpired Auth
1005 ErrCodeAuthNeed2FA Auth
1113 ErrCodeInsufficientBalance Quota
1302 ErrCodeRateLimitReached RateLimit
1305 ErrCodeServiceOverloaded Server
1308 ErrCodeUsageLimitReached Quota
1309 ErrCodeCodingPlanExpired Quota
1310 ErrCodeWeeklyMonthlyExhausted Quota
1311 ErrCodeModelNotIncluded Quota
1313 ErrCodeFairUsageViolation Quota
1314 ErrCodeEnterpriseExpired Quota
1315 ErrCodeEnterpriseKeyOnly Quota
1316–1321 usage-limit variants Quota
1210 ErrCodeInvalidParameter Parameter
1211 ErrCodeUnknownModel Parameter
1212 ErrCodeMethodNotSupported Parameter
1213 ErrCodeParameterMissing Parameter
1214 ErrCodeParameterInvalid Parameter
1215 ErrCodeParametersConflict Parameter
1221 ErrCodeAPITakenOffline Parameter
1222 ErrCodeAPINotExist Parameter
1261 ErrCodePromptTooLong Parameter
1301 ErrCodeUnsafeContent Content
1220 ErrCodeNoPermission Permission
-1 ErrCodeInternalError Server
1200 ErrCodeAPICallError Server
1230 ErrCodeProcessError Server
1234 ErrCodeNetworkError Server

本 client 未识别的错误码默认归为 ErrorCategoryServerIsRetriable: true——这是一个合理的默认值(把未知错误当作瞬时服务器问题 处理),但上表中列出的常量才是具有专门定制的 UserMessage 和重试决策的 那些。

事实来源:pkg/client/errors.go

HTTP 200 内嵌失败 的怪异行为

少数端点(Agents 的 Invoke/AsyncResult)即使在业务层面调用失败时也会 返回 HTTP 200——失败信息内嵌在响应体中,而非通过 HTTP 状态码指示。从这些 方法收到非 nil 的 error 意味着传输层失败;要检测一个成功响应内部的 业务级失败,请检查 resp.Failed()(或直接查看 resp.Error/resp.Status)。 两种响应类型都在其 Failed() 方法上对此做了说明——如果你只检查 err != nil,很容易遗漏这一点。