openrouter 403 报错

接入与开发

面向调用 OpenRouter 的开发者,讲清 403 报错常见成因与一步步排查方法,附对照表和适用边界。

本地跑得好好的脚本,换到 OpenRouter 就回一个 403,多数人第一反应是 Key 过期或余额不够,改来改去还是通不了。这篇不背概念,直接按排查顺序走:先分清 403 是哪一层拒绝的,再逐项对照请求头、模型权限、额度与区域限制,最后给出验证动作和什么情况下这套排法不适用。

403 到底是被哪一层拒的

403 最容易踩的坑是「只看状态码就开始改代码」。同是 403,可能是你家网络出口的网关拦的,可能是 OpenRouter 认出了你但觉得你没权限,也可能是它把请求转给上游模型厂商后被对方拒了。这三种的修法完全不搭界,先定位层,再动手。

本地网关或代理拦截
请求根本没到 OpenRouter,公司出口防火墙、自建反代、容器侧边车都可能返回 403,响应体常是自家网关的 HTML 或很短的提示
OpenRouter 侧鉴权通过但授权不足
key 被认出来了,但余额、权限范围、模型访问白名单、账号状态某一项不满足
上游模型提供商拒绝转发
OpenRouter 收下了请求,转发给具体模型的提供方时被拒,报错里通常点名某个上游
对比项401403
含义身份没被认出来身份认出来了但不让用
典型原因key 缺失、拼错、已失效余额、权限、模型白名单、地区或账号状态
排查起点先看请求头里 key 有没有带上、格式对不对先看响应体 message,再看是本地还是远端返回
改 key 有用吗大概率有用基本没用,换 key 往往还是 403
下一步动作核对鉴权头的完整性和有效性按层定位后查账户与模型权限状态

判断是谁拒的最快办法是看响应头和响应体的长相。本地网关返回的 403 一般没有 OpenRouter 的特征字段,body 是自家页面;OpenRouter 返回的通常是结构化 JSON,里面带 message,有时还有请求 ID;上游拒绝时消息里往往出现具体模型提供方的名字。把这三类特征记住,比背错误码有用。

  1. 原样保存一次失败请求把完整 URL、全部请求头(注意不要对外泄露 key)、请求体里的模型名和参数截下来存成文件,后面每一步都用它复现,不要凭记忆重写
  2. 记录报错原文和请求 ID连 message 里的每个字一起抄下来,别只留状态码;请求 ID 是找 OpenRouter 侧排查的唯一线索,没有它后面很难对账
  3. 先判断是不是本地拦的换一台不在公司网络里的机器、或换成直连再发一次同样的请求。如果这次通了,说明问题在你的网关或代理,去查那台设备的规则
  4. 读 message 再决定方向如果消息提到额度、权限、模型不可用、地区限制这类词,就是 OpenRouter 侧或上游侧的事,跟本地网络无关,别再折腾代理
  5. 按层验证OpenRouter 侧的问题到站内账户与用量相关页面核对当时的权限和额度状态,上游侧的问题换一个同类模型试试看是否只有特定模型报错

什么情况下这套方法不适用:如果请求根本没发出去(比如客户端在构造阶段就抛异常),你拿不到状态码也拿不到 message,那就得先解决代码问题;另外如果响应体被中间层改写或截断了,message 也读不到,这时候只能靠响应头特征和逐层替换法来定位。

按顺序过一遍排查清单

403 和 401 不一样:401 多半是密钥本身无效,403 是「身份没问题但这次请求不被允许」。所以排查顺序推荐从「你带过去的凭证」往「你所在的环境」推,一层层排除,别一上来就换 Key。下面这套顺序按排查成本从低到高排,照着走一遍基本能定位到方向。

  1. 第一步:确认用的是不是 OpenRouter 的 Key先把 Key 复制出来单独看一眼:是否被撤销、是否带多余空格或换行、开头前缀是否符合 OpenRouter 的格式。再确认调用地址是不是 OpenRouter 的接口域名——拿别家(比如某家官方 API)的 Key 去请求 OpenRouter 的地址,或者反过来,都会直接 403。验证方法:把同一个 Key 换成官方给的 curl 示例发一次最小请求,能通说明 Key 没问题。
  2. 第二步:检查请求头Authorization 的标准写法是 Bearer 加一个空格再加 Key,少空格、多回车、缩进错位都会翻车。用代码调试时特别容易被脚本里的换行符带进去。另外检查客户端或网关是否自带了代理头、鉴权头,被二次覆盖后服务端收到的就不是你写的那个值。验证方法:把实际发出的请求头原样打印出来,对比一次。
  3. 第三步:看模型权限与额度有些模型不是所有账号都能调,免费额度用完、余额不足、或者该模型的访问权限没开,都可能返回 403 而不是明确报错。这一层的口径随时会变,不要凭印象,到站内 OpenRouter 榜单页核对当前开放的模型和账号状态说明。
  4. 第四步:排除调用侧限制浏览器或移动端直连是最常见的坑:跨域和来源限制会让请求在服务端被拦;密钥如果曾经泄露、被平台标记过,也会触发风控拦截。这两种情况的表现都是「本地测不出来、线上必挂」。验证方法:换成服务端 curl 发同一请求,通得过就说明是前端直连的问题。
  5. 第五步:区域与合规部分模型对可用地区有要求,出口 IP 归属地不在允许范围时会直接拒绝。如果前面几步都正常,只剩这一层,就确认一下请求实际走的是哪个出口 IP、归属地是哪里,必要时换一个合规的中转出口再试。
排查层典型现象快速验证
Key 本身换示例也 403,且报错不带具体原因用官方 curl 示例发最小请求
请求头本地脚本通、线上不通,字段被改写打印真实请求头对比格式
模型与额度部分模型能调、部分不能到站内 OpenRouter 榜单页核对
调用侧限制浏览器/App 里必挂,服务端正常改用服务端发起同一请求
区域合规换网络环境后结果不同确认出口 IP 归属地

改完怎么验证真的通了

改完 Key、请求头或者权限设置之后,别急着把整套业务代码跑一遍。最省时间的做法是做减法验证:先发一个最小请求,确认基础调用能过,再一项项把你真实用的参数加回去。这样一旦又出现 403,立刻就能定位到是哪一项触发的,而不是对着一堆参数猜。

  1. 第一步:发最小请求只放一条 user 消息,不带 tools、不带 stream、不带 system,也不加任何额外请求头。能正常返回内容,说明 Key、账户状态、网络链路这几层基本是通的。
  2. 第二步:逐项加回真实参数每次只加一项,加完就发一次。建议顺序是:先加 system 提示,再加 stream,最后加工具调用。哪一步重新变成 403,问题就锁在这一项上。
  3. 第三步:换模型名做对照用同一个 Key、同样的请求体,只把模型名换成另一个你能确认可用的模型。换模型能过,说明问题在模型权限或路由上,而不是 Key 或网络。
  4. 第四步:把结果写进日志每次请求都记下状态码、报错原文、模型名、是否带工具和流式。下次再遇到同类报错,直接翻这份记录比对,不用从头试。
改动项预期结果如果还是 403 说明什么
最小请求(单条消息)正常返回Key、账户或网络层有问题,先别管参数
加回 system 提示正常返回系统提示里可能被判定成敏感内容
加回 stream正常返回流式本身或部分模型的流式支持受限
加回工具调用正常返回工具定义或调用方式触发了权限校验
换一个模型名正常返回原模型的访问权限没开,跟 Key 无关
  • 验证时一次只动一个变量,同时改两处就白测了
  • 对照模型要挑一个你确定以前能跑通的,别随手换一个没验证过的
  • 报错文本原样复制,不要自己概括成「权限错误」,概括会丢掉关键信息
  • 把每次验证的请求体也留一份,方便复现而不是靠回忆
  • 如果最小请求都不通,就别再调参数了,先去站内核对账户与权限状态
下一步想确认是不是模型权限问题,可以直接查各模型的可用状态与接入说明,路径在下面。

这些情况下这套排法不好使

前面那套逐项排查适合「单点问题」:key 写错、模型没开权限、请求头缺失。但它有个前提——报错真的来自 OpenRouter 官方那层,而且只卡你一个人。这个前提一旦不成立,继续按清单一项项过就是白费力气,得先判断自己遇到的是不是下面这几类特殊情况。

判断顺序可以反过来走:先看错误是不是你这边产生的,再看是不是大范围现象,最后才轮到账号本身。顺序错了,会花大量时间在无意义的字段核对上。

现象更可能的来源优先动作
报错体格式怪、字段和你平时见的不一样你自建的反代或中转层先翻那一层的访问日志和错误日志
所有模型、所有 key 一起挂账号被整体限制别逐项排查,直接找官方申诉入口
同一模型、同一时段很多人都在报上游策略临时调整先去站内服务监控页看是不是普遍现象
只有某个地区或某条链路报网络链路或节点问题换出口和节点验证,而不是改代码
  • 自建反代或中转层改写过响应体:403 可能是中间层自己抛的,不是上游返回的,排查入口在那一层
  • 账号被整体封停:现象和权限不足高度相似,逐项查 key 和模型基本没用
  • 上游临时调整策略导致的批量拒绝:同一模型同一时间段集中出现,属于外部事件
  • 单点权限问题:只有特定模型或特定 key 报,这才是前面排查清单的主场
  1. 第一步:确认报错是谁给的把原始响应体完整打印出来,对照你中间层自己定义的错误结构。如果字段名、包装层和你代码里的一致,基本可以判定是自家中间层返回的。
  2. 第二步:翻中间层日志去反代或中转服务的日志里按请求 ID 检索,看它有没有真的把请求转发出去、上游返回了什么。转发都没发生,就与上游无关。
  3. 第三步:判断是不是大范围同一模型同一时段如果集中出现大量相同报错,先去站内服务监控页核对当时的整体状态,再决定是改代码还是等恢复。
  4. 第四步:怀疑账号整体受限时直接申诉当所有模型、所有 key、所有节点都一致失败,且中间层日志显示上游确实返回拒绝,就该走官方申诉渠道,而不是继续单点验证。

常见问题

403 和额度不够是一回事吗?

不是。额度不足通常表现为限流或余额类提示,403 是授权层面的拒绝。但两者现象容易混:有些模型要在账户满足条件后才允许调用,条件不满足就回 403。先看响应体里的具体说明,再决定是补额度还是改权限,别一上来就充值。

同样的代码,昨天能用今天 403,为什么?

优先怀疑三件事:Key 被轮换或撤销、所调模型的可调用条件变了、账号触发风控。排查顺序是先用最小请求复现,再换模型名对照,最后检查 Key 是否还在有效列表里。如果多个模型同时挂,多半是账号或平台侧的问题,而不是你的代码。

用别人的 Key 或共享 Key 调,403 会更常见吗?

会。共享 Key 容易触发额度耗尽、并发异常或风控拦截,表现出来常是 403 而不是明确的额度提示。生产环境建议用独立 Key 并按用途拆分,方便把一次拒绝定位到具体调用方,也避免一人的异常影响整条链路。

本文依据各平台公开文档与官方公告整理,只做中文归纳;具体做法、参数与限制以官方文档为准。