GLM 错误码含义与处置对照
数据截至 2026-08,价格与限额以各官网为准。本文只讲计费与接入机制,不列具体价格数字。
智谱开放平台的报错是两层结构:外层 HTTP 状态码告诉你这是哪一类失败,响应体里的业务错误码才告诉你具体是什么失败。 只看 HTTP 状态码几乎必然误判——官方错误码表里挂在 429 下面的业务码有十几个,既包括真正的速率限制,也包括账户欠费、套餐到期、周期用量封顶、API Key 类型不匹配这些跟”请求太快”毫无关系的情况。把重试逻辑写成”看见 429 就退避重试”,遇到欠费那一类会白白重试到天亮。正确的做法是解析响应体里的 error.code,按业务码分派处置动作。另外还有一个坑:流式(SSE)调用在推理途中出问题时不会返回这些错误码,异常原因改从 finish_reason 里读。
先把两层结构分清楚
官方文档《错误码》页开门见山写明:调用智谱开放平台 API 时,接收到的响应码由两部分组成,外层是 HTTP 状态码,内层是响应体正文中定义的业务错误码,业务错误码提供了更具体的错误描述。
文档给的响应报文示例长这样,其中 401 是 HTTP 状态码,1001 是业务错误码:
< HTTP/2 401
< content-type: application/json
{"error":{"code":"1001","message":"Header 中未收到 Authentication 参数,无法进行身份验证"}}
注意 code 的值在 JSON 里是字符串形态的 "1001",不是数字 1001。用强类型语言反序列化的时候这里容易直接抛异常,写映射表时也别把两种形态混着比较。
工程上的建议是:在 HTTP 客户端外面包一层,先取 HTTP 状态码做粗分类(是不是 4xx、是不是 5xx),再取 error.code 做细分派,两者都记进日志。只记一个,事后复盘的时候基本查不出所以然。
401 一族:身份验证没过
官方表里挂在 401 下面的业务码是 1000、1001、1003、1005:
- 1000 身份验证失败:最笼统的一个,Key 本身不被认可。
- 1001:Header 中未收到 Authentication 参数,无法进行身份验证。这是压根没带鉴权头,或者头的名字写错了。官方接入文档里写明 API 密钥需通过 HTTP 请求头的 Bearer 认证方式提供,形式是
Authorization: Bearer YOUR_API_KEY。 - 1003:Authentication Token 已过期,请重新生成/获取。
- 1005:已开启二次认证保护,需要二次认证登录。
这四个的共同点是:重试没有任何意义。除非你在两次调用之间换了凭证,否则重试只会得到同样的 401。1003 是唯一一个可以做自动化的——如果你的凭证是有生命周期的 Token,可以在收到 1003 时触发一次刷新再重试一次,但要设重试次数上限,否则刷新逻辑一旦有 bug 就会变成死循环。
顺带一提,官方 FAQ 里提到 API Key 被删除后,该 Key 将无法再次成功调用接口,也不会产生扣费。所以线上突然大面积 401、而代码没动过的时候,先去控制台确认 Key 是不是被谁清理掉了,这比翻代码快得多。Key 本身的管理规范可以参考API Key 安全管理的通用做法。
400 一族:请求本身写错了
这一族是数量最多的,也是最好修的,因为错误信息里带占位符,直接告诉你是哪个字段出的问题:
| 业务码 | 官方错误信息(含占位符) |
|---|---|
| 1210 | API 调用参数有误,请检查文档 |
| 1211 | 模型不存在,请检查模型代码 |
| 1212 | 当前模型不支持 ${method} 调用方式 |
| 1213 | 未正常接收到 ${field} 参数 |
| 1214 | ${field} 参数非法。请检查文档 |
| 1215 | ${field1} 与 ${field2} 不能同时设置,请检查文档 |
| 1221 | API ${API_name} 已下线 |
| 1222 | API ${API_name} 不存在 |
| 1261 | Prompt 超长 |
${field} 这种写法说明返回给你的 message 里会填上真实字段名,所以日志一定要把完整的 message 打出来,只记一个 1214 等于把最有用的信息扔了。
几个容易踩的:
1211 和 1212 长得像但根因不同。 1211 是模型代码写错或者这个模型代码不存在;1212 是模型存在、但不支持你用的这种调用方式(比如你用了某种调用形态而该模型没开)。前者改模型名,后者要回官方文档确认这个模型支持哪些调用方式——这一条不能靠推断,也不能拿别的模型的支持情况类比,只能查对应模型的官方页面。
1215 是”互斥参数”。 两个参数不能同时设置。这种错误常见于框架封装:你以为只传了一个,SDK 或中间层偷偷给你补了另一个。排查时把最终发出去的请求体原样打出来看,别看你自己构造的那个对象。
1261 Prompt 超长是 400 而不是 429,说明它是”请求非法”而不是”额度不够”。这里要跟 finish_reason 里的 length 和 model_context_window_exceeded 区分开:1261 是请求进门就被拦下,后两者是已经开始生成之后才终止的。更细的排查路径可以看GLM API 报错排查。
403 与权限:1220
1220:您无权访问 ${API_name}。 官方错误码表里 1220 只占一行,没有再给典型诱因清单,文档里也没有找到第二处关于它的说明。所以能确定的只有错误码表本身给出的两点:一是它对应的 HTTP 状态码是 403 而不是 401,按 HTTP 语义,403 意味着身份是被识别的、卡住的是这个身份对该接口的访问权限;二是错误信息里带 ${API_name} 占位符,说明 message 会填上具体是哪个接口被拒。
工程上由此能推出的处置也就到这一步:它和 401 一族一样不属于”重试能解决”的类型,因为再打一次身份和权限都没变;但和 401 不同的是,换一把新 Key 通常也解决不了——401 是”你是谁没验过”,1220 是”你是谁验过了,但你不能碰这一个接口”。所以排查时第一步不是翻鉴权代码,而是把 message 里的 ${API_name} 完整取出来,确认被拒的到底是哪个接口,再拿这个接口名去平台侧确认开通状态。至于具体要开通什么、走什么流程,官方文档里没有找到相关说明,别自己编一套流程写进排障手册。
429 一族:最容易误判的一族
这一族是本文的重点。官方表里 429 下面挂了非常多的业务码,含义分散在四个完全不同的方向:
方向一,账户欠费。 1113:您的账户已欠费,请充值后重试。它挂在 429 下面这件事本身有点反直觉——按常识欠费应该是 402 之类。所以只按 HTTP 状态码写重试策略的系统,会把欠费当成限流一直退避重试。官方 FAQ 另外说明,欠费状态下可以使用有效期内的资源包,所以”欠费”和”完全不能调用”不完全等价,具体看你账户里资源包的状态。
方向二,真正的速率限制。 1302:您的账户已达到速率限制,请您控制请求频率。官方《速率限制》页给这一条列了典型原因和建议处理方式:典型原因是当前模型的并发请求数已达到账户上限、或短时间内请求过于密集;建议的处理方式是降低并发请求数量、增加请求队列或排队机制,必要时提升账户权益等级来提升并发额度(该条不适用 GLM Coding Plan 用户)。
这里有个概念要认准:官方明确写了并发数指的是同一时刻正在处理中的请求数量。它不是”每分钟多少次”,是”同时有几个在飞”。按次数节流的限流器管不住并发数,你得管在途请求数。
方向三,平台侧过载。 1305:该模型当前访问量过大,请您稍后再试。官方把这一类明确定性为平台服务过载,与单一账户的调用行为无直接关系,触发条件包括某一模型短时间内整体访问量激增、底层算力资源高负载、平台系统维护扩容或异常恢复。官方建议的处理方式是稍后重试、增加重试间隔避免立即高频重试、在业务允许的情况下降级或延迟处理。
1302 和 1305 的处置差别很大:1302 你改自己的并发就能缓解,1305 改自己没用,只能退避加降级。所以退避重试策略应该对这两个码分开配置。通用的退避与幂等设计可以对照API 429 的通用处理办法。
方向四,套餐与用量封顶。 这是 429 里最庞杂的一支,官方错误信息里带 ${next_flush_time} 这类占位符,会告诉你限额什么时候重置:
- 1308:已达到使用上限,限额将在下一个刷新时间重置。
- 1310:已达到每周/每月使用上限,限额将在下一个刷新时间重置。
- 1309:GLM Coding Plan 套餐已到期,需前往官方续订后恢复。
- 1311:当前订阅套餐暂未开放
${model_name}权限。 - 1313:账户当前使用模式不符合公平使用策略,请求频率已受到限制,官方指向的恢复路径是个人中心里的编程套餐总览页顶部申请解除限制。
- 1314:企业套餐已失效,请联系企业管理员。
- 1315:该 API Key 仅限企业编程套餐场景使用,需到官网更换对应产品类型的 API Key。
- 1316 到 1321 这一段:都是”周期用量封顶 + 无法转为超额按量付费”的组合,区别在于卡的是小时级窗口还是多天窗口、以及顶到头的是主账号余额、子账号月消费上限还是企业级月消费上限。这两种窗口具体按什么口径计算,官方错误信息里没有说明,别按”等到整点就恢复”这类假设去写等待逻辑——错误信息里给了重置时间字段,以它给出的时间点为准。
具体的时间窗口长度和额度数值我不在这里抄,因为这类数值随套餐调整会变,以官方文档和你控制台里的当前套餐说明为准。真正要记的是结构:这一支的处置动作既不是重试也不是降并发,而是等待重置时间点、或者去改账户侧的配置。程序上最合理的做法是收到这一段的码时直接熔断该通道,并把 message 里的重置时间提取出来告警给人,而不是继续打。
如果你写的是一张分派表,429 这一族至少要拆成四类:可退避重试(1302、1305)、需人工充值(1113)、需改账户或套餐配置(1309、1311、1314、1315)、等窗口重置(1308、1310、1316 一段)。
500 一族:服务端出问题
- HTTP 500 但业务码为空(官方表里这一行的业务码写作
-):内部错误。 - 1200:API 调用失败。
- 1230:API 调用流程出错。
- 1234:网络错误,错误信息里会带
${error_id},官方要求联系客服时提供这个 id。
1234 这个设计值得单独说:既然官方明确要求带着 error_id 找客服,那你的日志里就必须原样保留这个 id。很多团队的日志会把 message 截断或者做归一化处理,把可变部分抹掉以便聚合统计——一旦把 error_id 抹了,出事时就没法追溯了。建议对 1234 单独开一条日志规则,全量保留原始 message。
5xx 这一族是少数几个”重试确实合理”的场景,但要配幂等:如果你的业务侧对同一请求重复生成有副作用(比如按次计费的接口、或者会写库的流水),就要在应用层做去重键。
1301:内容安全审核
1301:系统检测到输入或生成内容可能包含不安全或敏感内容。 官方《内容安全》页给了比错误码表更细的说明:当 API 检测到模型输入或输出内容中含有违法及不良信息时,系统会向开发者返回错误码 1301、返回是输入(role = user)还是输出(role = assistant)触发的,以及严重程度 level。官方对 level 的说明是取值 0 到 3,level 0 表示最严重,3 表示轻微——这个方向是反直觉的,数字越小越严重,写判断条件时特别容易搞反。
官方给的错误响应示例里,这些信息放在跟 error 平级的 contentFilter 数组里:
{
"contentFilter": [
{ "level": 1, "role": "user" }
],
"error": {
"code": "1301",
"message": "系统检测到输入或生成内容可能包含不安全或敏感内容,请您避免输入易产生敏感内容的提示语,感谢您的配合。"
}
}
role 字段的价值很大:它直接告诉你是用户的输入被拦了还是模型的输出被拦了。前者应该在前端提示用户改措辞,后者应该按官方建议采取终止生成、撤回、修改、清屏、重启等措施删除已生成内容,并且不要把含违法及不良信息的内容再传回模型继续生成。这两种处置方式完全不同,只看 1301 是分不出来的,必须解析 contentFilter。
以上枚举与字段名以官方文档当前版本为准。
流式调用:错误码会”消失”
官方错误码页末尾有一条注,很容易被漏掉:使用流式(SSE)调用时,如果 API 在推理过程中异常终止,不会返回上述错误码,而是在响应体的 finish_reason 参数中返回异常原因。
这条注解释了一个常见的困惑:非流式调用报错报得很清楚,换成流式之后连接正常结束、HTTP 状态码也是 200,内容却是残缺的,日志里翻不到任何错误码。原因就是错误改从 finish_reason 走了。
官方对话补全接口的字段说明里,finish_reason 的取值含义是:stop 表示自然结束或触发 stop 词,tool_calls 表示模型命中函数,length 表示达到 token 长度限制,sensitive 表示内容被安全审核接口拦截(用户应判断并决定是否撤回公开内容),network_error 表示模型推理异常,model_context_window_exceeded 表示超出模型上下文窗口。取值清单以官方文档为准。
对照关系可以这样记:非流式下的 1301,在流式下对应 finish_reason 为 sensitive(官方内容安全页明确写了流式响应时 API 返回错误码 1301、V4 接口返回停止词 "finish_reason":"sensitive");非流式下的推理异常,在流式下对应 network_error。
所以流式链路的错误处理必须同时监控两处:连接层的 HTTP 错误和错误码,以及最后一个数据块里的 finish_reason。只做前者,你的告警系统会对着一堆 200 说一切正常。流式场景的更多断流原因可以看GLM 流式响应中断的排查。
落到一张可执行的分派表
把上面的东西收敛成工程规则,大致是四类动作:
- 不重试、报警给人:1000、1001、1005、1220、1113、1309、1311、1314、1315,以及 1301。这些重试多少次结果都一样,重试只是浪费额度和时间。
- 改代码后重发:1210 到 1215、1221、1222、1261。属于请求构造问题,程序自己修不了,要开发介入。
- 退避重试:1302、1305,以及 5xx 一族(500、1200、1230、1234)。1302 同时要降自己的并发,1305 只能等。
- 熔断到窗口重置:1308、1310、1316 到 1321 这一段。从 message 里把重置时间取出来,在那之前不要再打。
最后一个最容易栽的坑:别把 error.code 当数字比较。官方响应示例里它是带引号的字符串,你写 code == 1001 在弱类型语言里可能碰巧过、在强类型语言里直接不匹配,于是所有错误都掉进 default 分支被当成”未知错误”退避重试——包括那些永远不该重试的欠费和鉴权失败。这类 bug 平时不发作,一到线上出事就同时放大成本和故障时长。