跳转到主要内容
每个 BeeOS OpenAPI 非 2xx 响应(以及每个 is_error: true 的 SSE event: error / event: done)都携带一个稳定的机器可读 code 字段。本页是该 code 的单一真相源;wire 信封只是形状不同,词汇是一样的。 完整目录从 backend/shared/types/apierror/ 生成,跨 Gateway、Agent Gateway、A2A Gateway、MCP Gateway、OpenAPI Gateway 和内部服务共享。本表中的 code 是公开契约 —— 在 1.x 主线内形状不变。新增 code 是 minor 版本升级;改名或移除 code 是 major 版本升级。

错误怎么编码

阻塞 JSON 响应(任何 4xx / 5xx)

{
  "success": false,
  "error": {
    "type": "api_error",
    "code": "agent_not_found",
    "message": "Agent not found.",
    "details": {}
  }
}
HTTP 状态行携带与 error.code 相同的信息(见下表)。type 字段是 RFC 9457 problem-type(“api_error” / “invalid_request_error” / “authentication_error” / “permission_error” / “rate_limit_error” / “not_found_error” / “conflict_error” / “validation_error”); SDK 通常按 code 而非 type 分派。

SSE event: error frame(流式 invoke + 任务事件)

event: error
data: {"type":"error","code":"service_timeout","status_code":504,"message":"agent invocation timed out"}
code / status_code 与同等条件下阻塞 JSON 路径返回的完全一致。 完整 SSE frame 语义见 流式

SSE event: done 终止 frame

流以错误结束时,done.code 镜像 error frame 的 code,只消费 done 的客户端也能分派:
event: done
data: {"type":"done","text":"","context_id":"ch-...","is_error":true,"error":"agent invocation timed out","code":"service_timeout"}
有一个仅流式的 code 在阻塞 JSON 里从不出现:
  • agent_reply_error —— 智能体本身返回了带内错误消息 (agent_replyis_error: true)。HTTP / SSE 传输成功; 智能体报告了域级失败。done.text 携带智能体的错误文本。

Code 目录

4xx —— 客户端错误

codeHTTPwire 信封原因恢复
invalid_json400JSON请求 body 不是合法 JSON修客户端序列化器
invalid_body400JSONbody 已解析但 schema 校验失败message 哪个字段
invalid_param400JSON、SSE errorquery / path / body 参数被拒(如 taskId 空、deadline_ms > 7 天)修参数
missing_param400JSON缺少必填参数加上参数
unauthorized401JSONAuthorization header 缺失或非法刷新 / 重发凭证 —— 见 认证与 API Key
invalid_token401JSONJWT / oag_ 签名或 hash 校验失败unauthorized
missing_token401JSONAuthorization header 为空加上 header
forbidden403JSON、SSE error调用方不拥有智能体(且非公开)用拥有该资源的凭证
agent_not_found404JSON、SSE erroragentId(或 taskId)调用方 ACL 内不认识检查所有权 / 可见性
conflict409JSON、SSE error智能体拒绝调用(忙 / 拒接),或重复幂等 key 但 payload 已变,或任务终止messageagent rejected the request / task is already closed / duplicate idempotency key。仅对临时拒绝重试
payload_too_large413JSON请求 body 超过该路由大小上限catalog / instances / webhook 路由上限 64 KiB;invoke / tasks / conversations 上限 1 MiB。大附件用 POST /api/v1/files/presign-upload,别 inline 字节
rate_limited429JSON每调用方 × 每端点配额耗尽尊重 Retry-After;配额列在运维 runbook
login_rejected422JSON登录凭证错误(不是 refresh-token 失败)重新提示用户;不要清除现有 session

5xx —— 服务端错误

codeHTTPwire 信封原因恢复
internal_error500JSON、SSE error意外服务端故障(panic、marshal 失败等)指数退避重试;持续触发请报 bug
agent_offline503JSON、SSE error智能体记录存在但无活跃 session短暂重试;持续触发说明智能体 pod 挂了
agent_service_unavailable503JSON、SSE errorOpenAPI Gateway 丢失了到 Message Service / chatinvoke 的连接(如 MESSAGE_SERVICE_URL 未配置、MS 挂)重试;查平台健康
auth_unavailable503JSONAuth Service 不可达重试;不要强制登出
auth_transient503JSONAuth gRPC 临时抖动(超时 / 副本切换)重试;不要强制登出 —— wire 级 “session 未被杀” 信号
refresh_transient503JSONJWT 刷新因临时服务端故障失败重试;不要强制登出
session_unavailable503JSON基于 cookie 登录时 session 存储不可达重试登录
service_timeout504JSON、SSE errorOpenAPI Gateway 等智能体超时。timeout_ms 默认 120000(legacy)服务端钳制在 115000,让响应有预算 flush 在底层 http.Server.WriteTimeout(120s)触发前长任务用异步 tasks API;不要重试同一阻塞 invoke,因为智能体可能还在跑

仅流式 code

codeframe原因
agent_reply_errordone.code智能体返回了 is_error: trueagent_reply传输成功 —— 智能体本身失败。看 done.text 拿智能体的解释。

chatinvoke 哨兵 → wire code 映射

OpenAPI Gateway 的 invokeErrToAPIErrorhandlers_agents.go) 把 pkg/chatinvoke 的哨兵错误折叠成 wire 级 code:
chatinvoke 哨兵wire codeHTTP
ErrInvokerAgentNotFoundagent_not_found404
ErrInvokerTaskNotFoundagent_not_found404
ErrInvokerAgentOfflineagent_service_unavailable(msg = “agent is offline”)503
ErrInvokerMisconfiguredagent_service_unavailable(msg = “message service not configured”)503
ErrInvokerStreamUnavailableagent_service_unavailable(msg = “streaming not configured”)503
ErrInvokerTimeoutservice_timeout504
ErrInvokerTaskRejectedconflict(msg = “agent rejected the request”)409
ErrInvokerTaskClosedconflict(msg = “task is already closed”)409
ErrInvokerDuplicateconflict(msg = “duplicate idempotency key”)409
ErrInvokerPermissionDeniedforbidden403
其他internal_error500
:本契约 P0-B 之前版本在面向客户端的文档里用过不同的 codetask_rejected / agent_busy / agent_unavailable。那些从来 不是 wire code —— 实际 wire 一直是 conflict / agent_service_unavailable, 判别符在 message。SDK 客户端必须按本表的 code 值分派,不要 按旧版文档值。

TypeScript SDK recipe

try {
  const reply = await agents.invokeAgent({ agentId, invokeAgentRequest: { message } });
  // ... use reply
} catch (e) {
  if (e instanceof ResponseError && e.response.status === 504) {
    // service_timeout — switch to async tasks
  } else if (e instanceof ResponseError) {
    const body = await e.response.json();
    switch (body.error?.code) {
      case "agent_not_found":     /* surface "agent not found" */ break;
      case "forbidden":           /* user lacks permission     */ break;
      case "conflict":            /* agent busy / duplicate    */ break;
      case "agent_service_unavailable":
      case "agent_offline":       /* retry later               */ break;
      default:                    /* generic error             */ break;
    }
  }
}

Go SDK recipe

_, _, err := client.AgentsAPI.InvokeAgent(ctx, agentID).
    InvokeAgentRequest(req).Execute()
if err != nil {
    if apiErr, ok := err.(*beeos.GenericOpenAPIError); ok {
        var env struct {
            Error struct {
                Code    string `json:"code"`
                Message string `json:"message"`
            } `json:"error"`
        }
        _ = json.Unmarshal(apiErr.Body(), &env)
        switch env.Error.Code {
        case "agent_not_found":
            // ...
        case "service_timeout":
            // fall back to async tasks
        }
    }
}

另请参阅