Skip to main content
参考

错误处理与错误码

Qoder Agent SDK 分别报告任务失败、SDK 失败和进程退出。处理错误时应优先使用最具体的信号,而不是把所有非成功状态都当作异常。
哪里失败了?
   |
   +-- Agent 已结束任务,但任务未成功
   |      `result` 消息:subtype、errors、可选 error_code
   |
   +-- SDK 无法启动或维持会话
   |      抛出的异常:异常类型、code 和诊断字段
   |
   `-- qodercli 进程停止
          进程退出码:Transport 层诊断信息
Result 消息中的 error_code 和 qodercli 进程退出码属于两套不同的编号体系,不要用其中一套的数值匹配另一套。

推荐处理顺序

  1. 持续消费消息,直到 SDK 产出 result 或抛出异常。
  2. 收到 Result 后,先检查 subtype 和 is_error;只有在 error_code 存在时,才用它选择更具体的恢复策略。
  3. 在整个消息迭代外捕获 SDK 异常,根据异常类型和字段诊断配置、运行时或 Transport 问题。
  4. 记录会话 ID、Result subtype、错误码和异常名称。默认不要记录认证信息或完整源码内容。
一个失败会话可能先产出失败 Result,随后又因为进程非正常退出而抛出异常。可以同时记录两者用于诊断,但不要针对同一次失败向用户显示两次通知。

Result subtype

subtype含义建议处理方式
successAgent 已完成当前任务读取 result,继续会话或关闭会话
error_during_execution因执行、模型、服务、认证或不可恢复的工具错误而停止读取 errors;存在 error_code 时据此处理;只有瞬时故障才适合重试
error_max_turnsAgent 达到配置的最大轮数先检查循环或被阻止的工具,确认确实需要更多轮次后再提高限制
未来的运行时可能增加新的 Result subtype。应用应保留兜底分支,记录未知 subtype 和 errors,不要假设上表覆盖所有值。

处理 Result

TypeScript 的 SDKResultMessage.error_code 为可选的 number | string;Python 的 ResultMessage 提供可选的数值错误码。TypeScript 会原样保留 CLI 返回的 storage_insufficient 等字符串错误码,以及未知错误码。字段存在时可以据此处理,但不要通过解析面向用户的错误文本提取错误码。 Java 的 ResultMessage 没有错误码字段:outcome() 返回归一化结果 SUCCESS、ERROR 或 UNKNOWN,wireSubtype()、wireIsError() 和 errors() 对应 subtype、is_error 和 errors。需要 error_code 时,从 rawJson() 读取。
import {
  QoderCliProcessError,
  accessTokenFromEnv,
  query,
} from '@qoder-ai/qoder-agent-sdk';

let resultReceived = false;

try {
  for await (const message of query({
    prompt: '运行测试套件,并解释所有失败项。',
    options: { auth: accessTokenFromEnv() },
  })) {
    if (message.type !== 'result') continue;

    resultReceived = true;
    if (message.subtype === 'success' && !message.is_error) {
      console.log(message.result);
      continue;
    }

    console.error({
      subtype: message.subtype,
      errorCode: message.error_code,
      errors: 'errors' in message ? message.errors : [message.result],
      sessionId: message.session_id,
    });

    if (message.error_code === 105) {
      // 获取新凭据,并创建新的 SDK 会话。
    } else if (
      typeof message.error_code === 'number' &&
      [500, 10408, 10500].includes(message.error_code)
    ) {
      // 稍后使用有次数上限的指数退避重试。
    }
  }
} catch (error) {
  if (error instanceof QoderCliProcessError) {
    console.error({
      exitCode: error.exitCode,
      signal: error.signal,
      stderr: error.stderr,
      resultReceived,
    });
  } else {
    throw error;
  }
}

Result 错误码

当前 qodercli 会把下列数值码归一化,并可能通过 TypeScript 和 Python 的 message.error_code 返回;Java 从 ResultMessage.rawJson() 的 error_code 字段读取。该字段是可选字段;qodercli 也可能透传下表未列出的数值服务错误码。因此应保留未知值用于日志,并使用 subtype 和 errors 作为兜底。

认证与配额

错误码含义建议处理方式
105登录态或 Access Token 已过期获取有效凭据并创建新会话;注册认证过期回调
110达到当日用量限制等待用量周期重置,或检查账户限制
113用量配额耗尽检查配额和套餐状态,不要立即原样重试
114达到免费试用账户限制检查账户资格或升级选项
115达到免费用户配额等待配额恢复或检查升级选项
116团队管理员 Credits 耗尽由团队管理员补充或调整 Credits
117团队成员 Credits 耗尽请团队管理员分配或补充 Credits
118个人 Credits 耗尽补充 Credits,或使用仍有额度的账户
119所选模型的免费额度已用完选择可用模型、等待额度恢复或检查套餐
122Billing Group 的 Credits 达到上限请账单管理员检查 Group 限制

请求与策略

错误码含义建议处理方式
406因敏感内容或模型拒绝而阻止请求修改任务或输入内容,不要原样重试
416请求的范围或结构无法满足查看 errors,缩小或修正请求范围
430不支持请求的能力升级到兼容的 SDK/qodercli,或改用受支持的能力
47902达到 Agent 最大轮数提高轮数前先检查循环、权限和工具失败
48716Hook 阻止 Agent 执行检查对应 Hook 的决策,并修改 Hook 或任务
80411输入内容过长减少任务文本、附件或保留的上下文
80412图片或文档数量过多减少媒体附件数量后重试

服务与模型运行时

错误码含义建议处理方式
500请求或网络失败检查网络连接,使用有次数上限的指数退避重试
10408请求超时使用退避策略重试;反复超时时缩小任务范围
10500模型服务内部错误稍后重试;联系支持时保留会话 ID
10605模型请求正在排队qodercli 通常会等待并重试;如果最终 Result 仍返回此码,应稍后重试
只重试已确认属于瞬时故障的错误,并设置最大尝试次数、指数退避和随机抖动。认证、配额、策略、输入和配置错误必须先改变条件,再尝试运行。

SDK 异常

SDK 异常表示应用无法配置、启动、控制或继续会话,与 Agent 返回失败 Result 是两种不同情况。
场景TypeScriptPythonJava关键字段
未配置认证带 code: "auth_not_configured" 的 Error带 code: "auth_not_configured" 的 ErrorInvalidOptionsExceptioncode;Java getCode()
PAT 环境变量不存在AuthAccessTokenEnvVarErrorAuthAccessTokenEnvVarErrorAuthenticationExceptioncode;Java getCode()
Service Account 环境变量不存在AuthServiceAccountEnvVarErrorAuthServiceAccountEnvVarError—code
找不到或无法启动 qodercliQoderCliProcessErrorCLINotFoundError / CLIConnectionErrorCliNotFoundException、RuntimeInstallException,或错误码为 CLI_START_FAILED 的 QoderException错误消息;TypeScript stderr;Python 路径/消息;Java getCode()
qodercli 意外退出QoderCliProcessErrorProcessErrorCliProcessException;退出码 41 时为 AuthenticationExceptionexitCode / exit_code、stderr;TypeScript signal;Java getExitCode()、getStderrTail()
模型选择回调超时ModelPolicyTimeoutErrorModelPolicyTimeoutError不抛出异常,见表后说明timeoutMs / timeout_ms
协议版本不兼容ProtocolVersionMismatchErrorProtocolVersionMismatchErrorProtocolVersionMismatchExceptionCLI 和 SDK 的协议版本
运行时缺少所需能力UnsupportedCliCapabilityErrorUnsupportedCliCapabilityErrorUnsupportedCliCapabilityExceptioncapability;Java capabilityState()
CLI 在初始化完成前返回失败结果QoderCliInitializationError——message、code、result
Java 的模型选择回调超时不会以异常交给应用,catch 捕获不到。SDK 把错误码 MODEL_RESOLUTION_TIMEOUT 回给 CLI,并向诊断监听器发出 inbound_control_request_failed 事件,detail 含 error=MODEL_RESOLUTION_TIMEOUT。需要识别这种情况时注册 DiagnosticsListener,本轮结果按 ResultMessage.outcome() 处理,为 ERROR 时读取 errors()。 TypeScript 的 startup() 和 query.initializationResult() 在初始化完成前收到 CLI 失败 Result 时抛出 QoderCliInitializationError。message 保留 CLI 错误提示,code 保留可选的数字或字符串 error_code,result 保留完整原始结果。取消仍通过 AbortError 表达。初始化完成后的失败继续通过 Result 消息返回。 TypeScript 和 Python 共用的机器可读认证配置错误码如下:
code含义
auth_not_configured没有提供认证方式
auth_access_token_env_var_not_configured配置的 PAT 环境变量不存在
auth_service_account_env_var_not_configured配置的 Service Account 环境变量不存在
对于启动后发现的凭据过期,请使用 onAuthExpired / on_auth_expired,并用有效凭据创建新会话。Java 没有该回调,按 AuthenticationException 处理。详见 SDK 认证。

异常与错误码(Java)

Java SDK 自定义的异常都继承非受检的 QoderException,用 getCode() 取稳定的错误码。参数错误和配置错误在调用时同步抛出,例如 build() 校验失败抛出 InvalidOptionsException。启动和运行中的失败从消息游标的 hasNext() / next()、consume() 返回的 stage 或其他异步方法返回的 stage 交付;用 join() 等待时会包装成 CompletionException,用 getCause() 取出原异常。 SDK 不会自动重试,内置异常的 isRetryable() 都返回 false。常见错误码的处理方式:
错误码处理方式
INVALID_OPTIONS修正配置,重试没有意义
AUTHENTICATION_FAILED、CLI_AUTH_FATAL修正凭据或账号权限,再创建新的查询或会话
CLI_NOT_FOUND、RUNTIME_INSTALL_FAILED、CLI_START_FAILED、UNSUPPORTED_SECURE_SECRET_TRANSPORT检查 CLI 路径、托管 CLI 下载和启动环境,见问题排查
CLI_PROCESS_FAILED记录 getExitCode() 和 getStderrTail()
UNSUPPORTED_CLI_CAPABILITY当前 CLI 不支持所调用的功能。自行指定 CLI 时改用 SDK 托管的锁定版本,否则不使用该功能
SESSION_CLOSED资源已关闭,不要继续调用;需要时新建会话
MESSAGE_STREAM_ALREADY_CONSUMED每个消息流只能消费一次,openCursor() 和 consume() 合计只能调用一次
SPOOL_CAPACITY_EXCEEDED未消费的消息超过缓冲上限。及时读取消息流
以下错误码表示会话已经终止:QUERY_WRITE_FAILED(一次性查询的输入没有写入 CLI)、CONTROL_WRITE_FAILED(控制请求或响应没有写入 CLI)、TURN_ACCOUNTING_FAILED(轮次状态无法继续处理)、MESSAGE_DELIVERY_FAILED(一条缓冲消息无法解码)。原会话不能继续使用:关闭句柄,用 getCause() 记录原因;需要接着对话时,用原会话 ID 通过 SessionOptions.Builder.resume(String) 新建会话。 阻塞在 MessageCursor.hasNext() 或 next() 上的线程被中断时,抛出 ConsumerInterruptedException,线程的中断标志仍然保留。停止读取时关闭游标:
Java
try {
    while (cursor.hasNext()) {
        handle(cursor.next());
    }
} catch (ConsumerInterruptedException e) {
    // The interrupt flag is still set; stop reading and release the session.
    cursor.close();
}
关闭游标会异步关闭所属的查询或会话。完整的异常和错误码列表见 Java 异常一览。

qodercli 进程退出码

使用 SDK 的应用通常应处理 Result 和 SDK 异常,不应直接根据进程退出码编排业务逻辑。退出码主要用于 Transport 诊断,或直接启动 qodercli 的场景。
退出码含义
0进程正常退出
1通用或未分类失败
41认证失败;配置了认证过期回调时,SDK 也会触发该回调。Java 报告为错误码 CLI_AUTH_FATAL 的 AuthenticationException
42输入或命令行参数无效
44致命沙箱错误
52致命配置错误
53致命轮数限制错误
54致命工具执行错误
130取消或中断
其他退出码或终止信号可能来自操作系统、自定义运行时或子进程。TypeScript 通过 QoderCliProcessError.exitCode 和 .signal 暴露;Python 通过 ProcessError.exit_code 暴露可用的退出码;Java 通过 CliProcessException.getExitCode() 暴露。

日志与问题反馈

一条可用于排障的失败记录应包含:
  • SDK 语言和版本
  • system/init 消息中的 qodercli 版本(如果可用)
  • session_id、Result subtype、可选 error_code 和 errors
  • 异常类型、机器可读 code、进程退出码和信号
  • 失败发生在初始化前、工具调用期间,还是 Result 产生后
除非经过批准的排障流程明确需要,否则应隐去 PAT、Service Account Key、Authorization Header、完整任务文本、源码和工具输出。

下一步