故障排查
解决认证、路由、计费和流式传输的常见错误。
先看日志
修改配置之前,先打开仪表盘中的日志。每个失败请求的行都显示错误码、HTTP 状态和每次失败的上游尝试。开启请求捕获可以检查上游的完整报文。
认证错误
401 unauthorized
- 确认密钥以
sk-开头且完整。 - 在令牌管理中确认密钥已启用且未过期。
- 确认密钥所属的用户账户已启用。
- 确认请求头格式:
Authorization: Bearer sk-...或x-api-key: sk-...。
403 model_not_allowed
密钥开启了模型限制,且请求的模型不等于任何条目。把精确的逻辑模型名加入密钥的模型列表,或关闭模型限制。
403 ip_not_allowed
客户端 IP 不在密钥的 IP 白名单中。添加该地址或 CIDR 网段,或清空白名单。Monoize 位于反向代理之后时,确认代理转发了真实的客户端 IP。
路由错误
502 upstream_error
所有符合条件的路由都失败,或没有路由服务该模型。按以下顺序检查:
- 路由不存在。 确认已启用的 Provider 拥有一个已启用的 Channel,并用完整的 Billing Profile 映射该模型。
- 分组无交集。 密钥的分组必须与 Provider 至少共享一个分组。参见 API 密钥。
- 所有 Channel 不健康。 熔断器在冷却期内跳过不健康的 Channel。查看日志行中的失败尝试,找到根本的上游错误。
- 倍率上限。 设置了
max_multiplier的密钥会跳过价格高于上限的模型条目。
计费错误
402 insufficient_balance
用户余额或密钥的子账户余额为零或负数。请在用户中充值。保留独立余额的旧密钥会继续从其余额扣款,直到清零或删除;新密钥不再提供子账户选项。
402 api_key_spend_limit_reached
密钥的某个消费限额窗口已用尽。打开密钥的编辑对话框,提高或清空对应限额。小时窗口持续滚动;每日窗口在 UTC 零点重置。
费用看起来不对
费用 = 所选 Billing Profile 费率 × 有效倍率。先检查 Provider 默认 Profile 和倍率,再检查模型的 Profile 与倍率覆盖。
流式问题
流在响应中途停止
第一个响应字节之后,Monoize 绝不切换上游。中途断掉的流反映的是上游故障。查看日志行,并开启捕获查看上游原始帧。
客户端拒绝超长 SSE 帧
某些客户端限制 SSE 帧长度。在服务的 Provider 上添加 stream_split_sse_frames 变换。参见流式:拆分超长 SSE 帧。
客户端在长思考阶段后报告传输解码错误
错误文本为 Transport error: error decoding response body。Monoize 在每个 SSE 响应上发送 Cache-Control: no-cache 和 X-Accel-Buffering: no。仍然缓冲或压缩 text/event-stream 的反向代理可能截断流。为 Monoize 的 location 禁用代理缓冲。在 nginx 中设置 proxy_buffering off。确认代理不会 gzip 该事件流。
上游要求流式请求
添加 stream_force 变换,强制向上游发送 stream: true。客户端请求非流式时,Monoize 仍然向客户端返回非流式响应。
协议转换问题
400 empty_input_after_conversion
发送非空消息或完整会话历史。该错误表示转换后,可用的 Chat Completions 或 Responses Channel 没有可发送的消息。
通过 Chat Completions 发送工具结果时,同时包含对应的工具调用。将返回的 Monoize 响应 ID 用作 previous_response_id。使用同一个进程和 API key 续接。仅在兼容的 Responses 上游使用 conversation 和已保存的 prompt 对象。
Monoize 跳过消息为空的 Channel,并检查其余 Channel。若全部为空,它返回此错误,不调用上游,也不切换模型。流式请求收到错误事件。此检查无法恢复缺失的历史。复现前启用请求捕获,以定位内容丢失的位置。
400 invalid_request 提示 does not support thinking.type=adaptive
完整消息是 Messages model <名称> does not support thinking.type=adaptive。Monoize 在发出请求前校验每个已编码的 Messages 请求。它返回该错误,并且不调用任何上游。
Claude Code 在 /v1/messages 请求中发送 thinking: { "type": "adaptive" }。Monoize 为 messages 上游保留该对象。上游模型名必须表示支持 adaptive 的 Claude 模型。小写后的名称必须包含 claude,或以 opus-、sonnet-、haiku- 开头。DeepSeek/DeepSeek-V4-Pro 这类名称不满足条件,因此校验拒绝该请求。
采用以下任一修复方式:
- 改用 Chat Completions 发送该模型。 把 Channel 类型设为
chat_completion。或者在 Provider 上添加一条 API 类型覆盖规则,把该模型模式映射到chat_completion。规则模式匹配客户端发送的逻辑模型名,不是redirect目标。Monoize 随后按上游模型族编码推理控制字段。 - 只把 Claude 模型名重定向到 Claude 模型。 检查 Channel 的模型映射。把支持 adaptive 的 Claude 名称
redirect到其他模型族时,客户端的 Claude 专属控制字段仍留在请求中。参见 Provider 与 Channel。 - 在客户端关闭扩展思考。 不含
thinking对象的请求对非 Claude 模型可以通过校验。含thinking.type=disabled的请求同样可以通过。
对称情形返回 does not support thinking.type=enabled; use adaptive。当客户端发送手动 budget_tokens,而上游模型是 Opus 4.7 及更高、Sonnet 5 及更高、Fable 5 或 Mythos 5 时,出现该错误。修复方式相同。
转换后推理内容消失
某些上游用非标准字段返回推理内容。使用推理类变换还原或改写。从变换开始。
提供商私有字段没有到达上游
跨协议族转换会移除没有安全目标表示的提供商私有嵌套字段。使用 field_set 变换为某个 Provider 重新写入字段。
客户端拒绝工具调用中的 4338.0 这类数字
部分上游在工具调用参数里把整数写成 JSON 浮点数。Codex 的 write_stdin 把 session_id 解析为整数,并拒绝 4338.0。Monoize 在把响应发给客户端之前,会把工具调用参数中的整数值浮点数改写为 JSON 整数。此改写不需要变换规则。
仪表盘访问
管理员密码丢失
另一个 super_admin 可以在用户中重置密码。没有其他 super_admin 时,直接在数据库中重置。
第一个账户不是管理员
第一个注册的账户成为 super_admin。此规则只生效一次。之后的账户默认为 user。