错误处理
错误可能出现在四层:HTTP 状态码、统一返回结构、JSON-RPC 的 error 对象,以及 MCP tools/call 结果中的 isError 标记。
通常按以下顺序检查,再看具体 API 的字段:命令看 status 和 exit_code,文件看 data.error_type,代码单元看 outputs。流式接口例外:WebSocket 可能在握手成功后才报告错误。
失败位置
不同 plane 的失败表现并不相同,这是有意设计的。例如,退出码为 1 表示命令已经执行,只是命令本身失败;而不存在的文件则根本没有读成功。
- 非零退出码不是传输层错误。例如执行
exit 3时,POST /v2/commands仍返回200、success: true、status: "completed"和exit_code: 3。 - 如果等待时间到了但命令仍在运行,返回
status: "running",而不是超时错误。 - 代码单元失败时,响应返回
200和success: false,data.status为"error",错误信息在outputs的 traceback 中。 - 不存在的会话或命令 id,在各执行 API 上都返回
404。 WebSocket 会先以101完成握手,再发送{"type": "error", "data": "Session not found"}并关闭连接。监听器的 SSE 流会在建立连接前返回404。
返回结构
v1 和大多数 v2 接口共用同一个返回结构:
success: false 表示 aiod 已理解请求,但操作失败。此时读取 message;如果 hint 不为空,也一并读取。它不是传输层错误。
校验错误
请求未通过 schema 校验时返回 422,每个 plane 都一样:
query 字段使用同一套校验。字段缺失时,location 是 ["query", "path"];类型错误时,location 只有 ["query"]。
反序列化器会给出错误原因(例如 invalid digit found in string),但不会指出具体字段名。
请求体缺失按 {} 处理:字段全是可选的路由可以不带 body 调用,带必填字段的路由则返回校验错误。
文件错误
文件接口的失败带一个结构化的 data 对象,而不是一段 message 文本:
/v2/fs 和 /v1/file 返回相同的 data 对象,区别只在外层 HTTP 状态码。
retryable 用来区分两类失败:锁被短暂占用等临时性失败,重试可能成功;路径写错等持续性失败,在修正原因前重试不会成功。
error_type 与状态码的对应关系见 File(文件)。
HTTP 状态码约定
这些状态码在不同路由上可能有多种触发原因:
MCP 工具错误
tools/call 在工具内部失败时,仍返回正常的 JSON-RPC 结果,只是带有 isError 标记。这不是 HTTP 错误:传输成功了,但工具执行失败。
isError 包括以下情况:
- 参数缺失或非法,例如
sandbox_execute_bash不带cmd时返回cmd is required。 - 文件 API 的任何失败,此时结构化错误对象会作为结果文本返回。
- CDP 端口无响应时调用
browser_get_info,或没有 computer-use worker 时调用browser_gui_screenshot、browser_gui_execute_action。 - 调用
EXTRA_MCP_SERVERS中已停止的上游。此类上游也不会出现在tools/list中。
名字不存在则属于协议错误:/mcp 返回 200,响应体是 JSON-RPC 的 error 对象,方法名不存在是 -32601,工具名不存在是 -32602。请求体不是 JSON 则是 -32700。
客户端处理
返回结构和 plane 自己的执行结果是两层信息,都需要检查。客户端通常只负责处理 success: false;退出码和代码单元状态仍需由调用方读取:
同样三次读取的 TypeScript 版本:
遇到 retryable: true 或 503 可以重试;429 则应退避后再试。400、404、409 和 422 通常不会自行恢复,直接重试没有意义。
相关页面
- File(文件) —— 结构化文件错误及其状态码
- Commands(命令执行) —— 命令生命周期和退出码
- Terminals(PTY 终端) —— 会话和流式接口的失败
- 鉴权 —— 什么情况返回
401