错误码与分类
网关的错误有两层表示:后端各服务层产出的原始分类(category,snake_case 标识符),以及控制台把它归并成的面向操作员的错误类(class)。分类决定重试与冷却行为,错误类决定界面上显示什么标题与修复建议。 proxy_logs 与响应体里携带的是原始分类;控制台展示的是错误类。
错误类
共 13 个错误类。
| 错误类 | 含义 |
|---|---|
network | 连不上上游:DNS、TLS、超时、连接被拒 |
auth | 凭据或令牌被上游拒绝 |
config | 本地的地址、配置或输入不合法 |
upstream_shape | 上游返回的形状不是这个协议应有的形状 |
missing_key | 没有可用的上游凭据 |
missing_user_token | 缺少用户令牌(该渠道需要用户自带凭据) |
rate_limited | 被上游或本地限流 |
upstream_reject | 上游明确拒绝了这次请求 |
pinned_upstream | 固定成员(single_member_id)不可用 |
not_found | 模型或资源不存在 |
server | 网关侧错误 |
cancelled | 客户端取消或超时 |
empty_response | 上游返回了空响应 |
分类 → 错误类
下表由 web/src/errorCatalog.ts 生成。它是跨服务层的分类总表——后端新产出一个分类而这里没有对应项时,控制台会把它渲染成通用兜底文案。
共 102 个已知分类。
| 分类 | 错误类 |
|---|---|
transport | network |
upstream_failure | network |
connection_failed | network |
unreachable | network |
timeout | network |
dns_failure | network |
tls_failure | network |
outbound_blocked | network |
body_read_timeout | network |
unauthorized | auth |
upstream_unauthorized | auth |
invalid_token | auth |
auth_failed | auth |
upstream_status_401 | auth |
upstream_status_403 | auth |
user_token_not_for_models | auth |
session_expired | auth |
invalid_base_url | config |
invalid_url | config |
site_unavailable | config |
channel_disabled | config |
credential_unavailable | config |
credential_disabled | config |
unsupported_adapter | config |
invalid_metadata | config |
validation_error | config |
invalid_channel_id | config |
invalid_id | config |
identity_conflict | config |
unsupported_format | config |
config_incomplete | config |
body_too_large | config |
unsupported_path | config |
unsupported_feature | config |
adapter_request | config |
invalid_payload | upstream_shape |
no_credential | missing_key |
missing_api_key | missing_key |
keys_masked | missing_key |
key_masked | missing_key |
skipped_masked | missing_key |
empty_token_list | missing_key |
token_created_but_secret_masked | missing_key |
already_has_api_key | missing_key |
user_credential_unavailable | missing_user_token |
no_user_token | missing_user_token |
rate_limited | rate_limited |
upstream_status_408 | rate_limited |
upstream_status_429 | rate_limited |
upstream_status | upstream_reject |
upstream_status_400 | upstream_reject |
upstream_status_404 | upstream_reject |
upstream_status_500 | upstream_reject |
upstream_status_502 | upstream_reject |
upstream_status_503 | upstream_reject |
upstream_status_504 | upstream_reject |
content_blocked | upstream_reject |
preferred_channel_unavailable | pinned_upstream |
pinned_upstream_not_member | pinned_upstream |
pinned_upstream_member_disabled | pinned_upstream |
pinned_upstream_channel_disabled | pinned_upstream |
pinned_upstream_no_credential | pinned_upstream |
pinned_upstream_cooling_down | pinned_upstream |
pinned_upstream_invalid_weight | pinned_upstream |
no_eligible_upstream | pinned_upstream |
channel_not_found | not_found |
route_not_found | not_found |
credential_not_found | not_found |
plugin_not_found | not_found |
not_found | not_found |
internal_error | server |
server_error | server |
persistence_failure | server |
encryption_failed | server |
decrypt_failed | server |
response_too_large | server |
plugin_market_unavailable | network |
plugin_release_fetch | network |
plugin_release_asset_unavailable | network |
plugin_release_version_invalid | config |
plugin_artifact_download | network |
plugin_artifact_read | network |
plugin_artifact_checksum_mismatch | config |
plugin_artifact_size_mismatch | config |
plugin_artifact_too_large | config |
plugin_manifest_entrypoint_missing | config |
plugin_manifest_entrypoint_invalid | config |
plugin_manifest_missing_entrypoint | config |
plugin_manifest_invalid_id | config |
plugin_manifest_invalid_config | config |
plugin_manifest_invalid_permissions | config |
plugin_archive_path_invalid | config |
plugin_archive_path_escape | config |
plugin_archive_symlink_rejected | config |
plugin_health_check_failed | network |
plugin_stage_create | server |
plugin_stage_write | server |
plugin_replace_failed | server |
plugin_entrypoint_unavailable | server |
cancelled | cancelled |
stream_interrupted | network |
empty_response | empty_response |
转发层产出的分类
下表由 internal/proxy/proxy_classify.go 的 return 语句生成,是转发层实际会写进日志的分类。它同时决定该次失败是否可重试:可重试的失败会累加成员失败计数并触发冷却。
| 分类 | 控制台错误类 |
|---|---|
adapter_request | config |
cancelled | cancelled |
content_blocked | upstream_reject |
empty_response | empty_response |
invalid_url | config |
response_too_large | server |
transport | network |
unsupported_feature | config |
unsupported_path | config |
动态分类:upstream_status_<code>
上游返回非成功状态码时,分类不是固定字面量,而是 upstream_status_ 加 HTTP 状态码(例如 upstream_status_429)。控制台的分类表里只显式列出了需要区别对待的几个,其余按前缀规则落到同一个错误类。
两处一致
转发层产出的每一个分类都能在控制台分类表里找到对应项。这一节在出现差集之前不会列出任何内容,所以它空着就是好消息。
控制台文案键覆盖
日志页的错误标签直接由 logsPage.errorClass.<错误类> 渲染,所以错误类缺翻译时界面上会直接显示出原始键名。注意 i18n 的 parity 测试抓不到这种漏配——它只比较 zh 与 en 是否互相一致,两边一起缺也能通过。
| 语言 | 已覆盖 | 缺失 |
|---|---|---|
zh | 13 / 13 | — |
en | 13 / 13 | — |
两种语言的每一个错误类都有对应文案。