RouteMux Docs

错误处理

依据 retry.strategy、retry.retryable 与 billing.status 决定下一步,而不是为每个错误码写一个分支。

每个 RouteMux 错误都用三个结构化字段回答「我的代码接下来该怎么办」。请按这些字段判断, 不要为每个错误码各写一个分支——错误码会随产品增加,而按这些字段写的代码不需要跟着改。

一段能直接抄的处理逻辑

async function callWithRouteMuxHandling(send) {
  for (let attempt = 0; ; attempt++) {
    const res = await send();
    if (res.ok) return res;

    const { error } = await res.json();

    switch (error.retry.strategy) {
      case 'BACKOFF': {
        if (attempt >= 5) throw new Error(error.code);
        // 服务端给了延迟就用它的
        const base = error.retry.retry_after_seconds ?? Math.min(2 ** attempt, 30);
        await sleep((base + Math.random()) * 1000); // 加抖动
        continue;
      }
      case 'RETRY':
        if (error.retry.retryable && attempt < 3) { await sleep(500); continue; }
        throw new Error(error.code);

      case 'TOP_UP':        return promptUserToAddCredit(error);
      case 'SWITCH_MODEL':  return retryWithAnotherModel(error);
      case 'AUTHENTICATE':  return fixApiKey(error);
      case 'FIX_REQUEST':   throw new Error(error.message); // 重试不会有任何变化
      case 'CONTACT_SUPPORT':
        throw new Error(`${error.reference} · ${error.request_id}`);
      case 'NONE':
        return null; // 没有需要你处理的失败
    }
  }
}

两个 retry 字段回答的是不同问题

字段它回答什么
retry.retryable同一个请求原样再发一次,有没有可能成功?
retry.strategy要真的成功,该改哪里

两者相互独立。看几个"取值不一致"的例子就明白了:

错误retryablestrategy为什么两个都对
MODEL_UNAVAILABLEtrueSWITCH_MODEL模型可能会回来,重试不算白费;但换个模型更快。
JOB_ARTIFACT_NOT_FOUNDfalseRETRY那个产物已经永久删除,重查拿不到;有意义的是重新发起一个任务
PLATFORM_INTERNAL_ERRORtrueCONTACT_SUPPORT值得重试一次;但反复出现就是我们的问题,不是你的。

八个 strategy 分别是什么意思

retry.strategy含义你该做什么
FIX_REQUEST请求本身不被接受改请求。重试没有任何意义REQUEST_INVALIDMODEL_VISION_UNSUPPORTED
AUTHENTICATE凭据有问题修或更换 API key,不要重试AUTH_INVALID_API_KEYAUTH_API_KEY_EXPIRED
BACKOFF暂时拥堵等待后重试,遵守 Retry-AfterMODEL_BUSYLIMIT_RATE_EXCEEDED
RETRY瞬时失败可以重试,无强制等待REQUEST_TIMEOUTJOB_FAILED
SWITCH_MODEL这个模型处理不了换一个模型MODEL_NOT_FOUNDMODEL_ACCESS_DENIED
TOP_UP余额不足充值后重新发送BILLING_INSUFFICIENT_CREDITS
CONTACT_SUPPORT你这边改不了带上 reference request_id 联系客服AUTH_ACCOUNT_SUSPENDEDPLATFORM_PRICING_INCOMPLETE
NONE无需处理继续JOB_NOT_CANCELLABLE

退避要怎么退

当一个错误带了等待时长,RouteMux 会同时放在两个位置,用你客户端好取的那个:

  • 响应头 Retry-After,单位秒
  • 响应体里的 error.retry.retry_after_seconds

例如 MODEL_BUSY 给的是 5。没有给时长时,请用指数退避,并且一定要加抖动—— 否则同一时刻失败的所有客户端会在同一时刻重试,把你正要躲开的那个尖峰原样重建一次。

这次扣钱了吗

error.billing.status 告诉你这次失败的请求有没有花钱。

取值含义能安全重试吗
NOT_BILLED没有扣费可以,不存在重复扣费风险
BILLED失败前已经消耗了额度重试会再次计费,请自行判断

目前目录里的每一个错误都是 NOT_BILLED:被这些错误码拒绝的请求不收费,所以按 strategy 重试不会造成重复扣费。BILLED 只会出现在请求日志里——那是失败发生前用量 已经结算的情况。

涉及钱的问题,以请求日志为准。唯一可能出现"响应体与最终计费不一致"的情形,是流式 请求在已经产出 token 之后失败。

两件不要做的事

不要按 message 分支。 它会随 Accept-Language 本地化,也会随产品迭代改写。 请按 code 分支,message 只拿来展示给人看。

不要重试 FIX_REQUEST 类错误。 请求没有任何变化,结果也不会变。目录里大约一半的 错误码属于这一类——一个无脑「任何错误都重试三次」的封装,会把重试预算全花在根本不可能 成功的请求上。

查具体某个错误

全部错误码与 RMX-… 编号都在错误参考页,可搜索,每条都有永久锚点, 可以直接把链接发给客服。

On this page