跳转至

错误码对照表

文档版本: 1.1.0 最后更新: 2026-10-15 适用版本: v3.3.3+ 作者: AI Assistant

JAiRouter 使用标准化的错误码系统来标识各种错误情况,便于客户端进行错误处理。

⚠️ 响应形状按入口面不同:/api/**(控制台面)用下面表格里的 RouterResponse 形状(errorCode 字段);/v1/**(OpenAI 面)用嵌套的 {"error":{"message","type","code"}}(见 统一 API 接口);/v1/messages(Anthropic 面)用 Anthropic 的 {"type":"error","error":{...}} 形状。另有两个已知例外不走本表:管理面限流 429 返回 {"code":"RATE_LIMIT_EXCEEDED","message":...}(扁平体、没有 error 包裹);异常处理器兜底返回数字码(如 {"code":"500"})。

📌 本表的权威来源是代码:本表与 common/constants/ErrorCode.java(错误码注册表,62 个会被真正发出的码)逐条对账, 由 scripts/docs/check-error-codes.py 在 CI 里双向校验 —— 文档漏列一个注册表里的码、或文档列了一个发不出来的码,都会判红。 每个码的「状态由哪条链决定」也登记在注册表里(渲染路径),因此改码名/改状态前先改注册表。

错误响应格式

{
  "success": false,
  "message": "错误描述",
  "errorCode": "ERROR_CODE",
  "data": null
}

HTTP 状态码映射

HTTP 状态码说明错误类别
400请求参数错误验证错误
401未认证认证错误
403权限不足授权错误
404资源不存在资源错误
409资源冲突业务错误
429请求过多限流错误
500服务器内部错误系统错误
502网关错误下游服务错误
503服务不可用下游服务错误

认证错误码 (Authentication)

HTTP 状态码: 401 Unauthorized

这一节的码由认证异常承载(注册表里的渲染路径是认证链):客户端可见状态来自异常携带的 401, 不是由错误码命名规则推导的 —— 例如 INVALID_API_KEY 的规则链推导值是 400,但客户端拿到的是 401。

错误码描述常见原因解决方案
INVALID_API_KEY无效的 API KeyKey 不存在、格式错误、来源 IP 不在白名单、或已被禁用核对 Key 与调用来源
EXPIRED_API_KEYAPI Key 已过期Key 超过有效期重新生成 API Key
EMPTY_API_KEY未携带 API Key请求头缺少 X-API-Key添加 X-API-Key 请求头
API_KEY_DISABLEDAPI Key 认证功能未启用服务端关闭了 API Key 认证打开服务端开关
API_KEY_AUTH_FAILEDAPI Key 认证失败校验链抛出未预期异常查服务端日志定位根因
DAILY_QUOTA_EXCEEDED超过每日请求配额Key 的每日请求数已用尽等次日重置或提升配额
TOKEN_QUOTA_EXCEEDED超过每日 Token 配额Key 的每日 Token 数已用尽等次日重置或提升配额
RATE_LIMIT_EXCEEDED请求频率超过限制超过 Key 的每分钟限速(见「限流错误码」一节的双状态说明)退避后重试
JWT_INVALIDJWT 令牌校验失败签名不匹配或格式错误重新登录获取新令牌
JWT_EXPIREDJWT 令牌已过期令牌超过有效期刷新或重新登录
EXPIRED_JWT_TOKENJWT 令牌已过期(按 expired 归类)校验链报 expired 时由认证管理器归类重新登录
JWT_BLACKLISTED令牌已被列入黑名单令牌已注销或被吊销重新登录获取新令牌
JWT_VALIDATION_ERRORJWT 校验过程中发生错误校验时抛出异常查服务端日志
JWT_REFRESH_EXPIREDJWT 令牌超出刷新窗口刷新窗口已过重新登录
JWT_REFRESH_ERRORJWT 刷新过程中发生错误刷新时抛出异常查服务端日志
JWT_REFRESH_FAILEDJWT 令牌刷新失败刷新链抛出异常重新登录
JWT_USER_ID_EXTRACTION_FAILED无法从 JWT 令牌中提取用户 ID令牌缺少可解析的用户标识重新登录
JWT_AUTH_FAILEDJWT 认证失败认证管理器抛出未预期异常查服务端日志
JWT_DISABLEDJWT 认证功能未启用服务端关闭了 JWT 认证打开服务端开关
TOKEN_REQUIRED刷新时未携带当前令牌刷新请求缺少当前令牌携带当前令牌再刷新
EMPTY_JWT_TOKEN未携带 JWT 令牌请求头缺少 Jairouter_Token添加 Jairouter_Token 请求头
AUTH_MISSING请求缺少认证信息既未带 API Key 也未带 JWT补齐认证凭据
AUTH_FAILED认证失败(默认码)认证过滤器兜底查服务端日志确认具体原因
AUTH_ERROR认证过程中发生未知错误认证链抛出未识别异常查服务端日志
UNSUPPORTED_AUTH_TYPE不支持的认证类型客户端用了本网关不识别的认证方式改用 API Key 或 JWT
LOGIN_FAILED登录失败用户名或密码错误检查登录凭据

示例响应:

{
  "success": false,
  "message": "无效的API Key",
  "errorCode": "INVALID_API_KEY",
  "data": null
}


授权错误码 (Authorization)

HTTP 状态码: 403 Forbidden

错误码描述常见原因解决方案
FORBIDDEN禁止访问通用授权失败检查角色和权限
FORBIDDEN_TOKEN_USAGE无权查看该令牌的用量令牌不属于当前调用者用所属账号查询该令牌
BUILTIN_READONLY内置项只读试图修改/删除内置适配器改为新建自定义适配器

⚠️ INSUFFICIENT_PERMISSIONS / ACCESS_DENIED / FORBIDDEN_RESOURCE 曾在 AuthorizationException 里声明,但 全仓没有发出点(其工厂方法只被单元测试调用)⇒ 已随未接线代码一并删除(#406),本表不列:客户端照它们写分支永远命中不到。 真正的 403 由 Spring Security 的授权链与上表的 FORBIDDEN 承担。 BUILTIN_READONLY 由 AdapterConfigController 的 PUT/DELETE 内置分支显式写成 403;按 issue #405 的混合方案,同码的规则链推导值也已对齐为 403 ⇒ 两端一致。


资源错误码 (Resource)

HTTP 状态码: 404 Not Found

错误码描述常见原因解决方案
NOT_FOUND资源未找到请求的资源不存在检查资源 ID 或路径
TEMPLATE_NOT_FOUND模板不存在模板 ID 不存在检查模板 ID
TOKEN_NOT_FOUND令牌不存在令牌 ID 不存在检查令牌 ID
ADAPTER_NOT_FOUND适配器不存在适配器名称不存在检查适配器名称

ApiException.resolveStatus 还会把任何以 _NOT_FOUND 结尾的未登记码按规则映射为 404; 上表是已登记的四个码。


请求校验错误码 (Validation)

HTTP 状态码: 400 Bad Request

错误码描述常见原因解决方案
INVALID_REQUEST请求不合法参数格式或值错误检查请求参数
INVALID_PARAM参数无效参数值超出范围检查参数约束
INVALID_PAGE分页参数不合法页码小于 0传合法页码
INVALID_SIZE分页大小不合法页大小超出 1-100传合法页大小
INVALID_TOKEN_ID令牌 ID 不合法令牌 ID 为空或格式错误检查令牌 ID
INVALID_TYPE类型不合法类型取值不在枚举内检查类型取值
INVALID_NAME名称不合法名称缺失或为空传非空名称
INVALID_PERMISSION权限项不合法权限码不在权限清单内用已登记的权限码
INVALID_RECORD_LEVEL记录级别不合法记录级别不在枚举内用 METADATA_ONLY / SUMMARY / FULL
INVALID_ROLE角色名不合法角色名不在已知角色内用已知角色名
RESTART_REQUIRED需要重启后生效提交了不支持热改的字段移除这些字段,改配置文件后重启

⚠️ RESTART_REQUIRED 的端点实测值与规则链推导值现在都是 400 —— 按 issue #405 的混合方案, 每条链先按自己的语义定状态(本码 = 请求校验语义 400),再把两端对齐:规则链对同码原先推导 403, 已改为 400。同一方案把 BUILTIN_READONLY 定为授权语义 403,故它已移入「授权错误码」一节。 上一版还列过 VALIDATION_ERROR(只是 ValidationFailureType 的枚举值,从不作为响应码发出)、 INVALID_PARAMETER / MISSING_PARAMETER / INVALID_FORMAT(全库无匹配)—— 均已从本表移除。


业务冲突错误码 (Business)

HTTP 状态码: 409 Conflict

错误码描述常见原因解决方案
CONFLICT_STATE资源冲突资源当前状态不允许该操作检查资源状态
CONFLICT_EXISTS资源已存在同名资源已存在换名称或改为更新
CONFLICT_BUILTIN与内置项冲突试图覆盖内置项换名称

冲突码的真实形态是 CONFLICT_STATE(由异常映射)以及共用前缀的端点级变体 CONFLICT_EXISTS / CONFLICT_BUILTIN;不存在裸 CONFLICT。 ApiException.resolveStatus 把任何 CONFLICT* 归 409。


限流错误码 (Rate Limit)

HTTP 状态码: 429 Too Many Requests(管理面)· 401(API Key 校验链)

错误码描述响应头解决方案
RATE_LIMIT_EXCEEDED超过限流阈值Retry-After / X-Quota-*(管理面)/ 无(校验链)等待令牌恢复后重试

⚠️ 同一个码在两条真实路径上对应两个状态(issue #404,待裁定): ① 管理面限流器(AdminApiRateLimiter)直接写 429 扁平体 {"code":"RATE_LIMIT_EXCEEDED","message":...}; ② API Key 校验链(ApiKeyValidator → FullValidationResult.toException())把它装进 AuthenticationException, 客户端拿到 401。按状态码分支的客户端需要同时处理这两种情况。

响应头没有 X-RateLimit-Reset / X-RateLimit-Remaining(全仓无此头);配额超限实际写 Retry-After 与 X-Quota-*(limit / remaining / window)。原表里的 GLOBAL_RATE_LIMIT / SERVICE_RATE_LIMIT / INSTANCE_RATE_LIMIT 全库无匹配,已删除。


服务与系统错误码 (System)

HTTP 状态码: 500 Internal Server Error

错误码描述常见原因解决方案
INTERNAL_ERROR服务器内部错误未预期的异常检查服务日志
ADD_FAILED新增失败黑名单等新增操作失败查服务端日志
BATCH_TOKEN_REVOKE_FAILED批量吊销令牌失败批量吊销过程异常查服务端日志
BLACKLIST_STATS_FAILED获取黑名单统计失败统计查询异常查服务端日志
CLEANUP_FAILED清理失败清理操作异常查服务端日志
GET_CLEANUP_STATS_FAILED获取清理统计失败统计查询异常查服务端日志
GET_TOKENS_FAILED获取令牌列表失败列表查询异常查服务端日志
GET_TOKEN_DETAILS_FAILED获取令牌详情失败详情查询异常查服务端日志
TOKEN_REFRESH_FAILED令牌刷新失败刷新过程异常重新登录
TOKEN_REVOKE_FAILED令牌吊销失败吊销过程异常查服务端日志
SANITIZATION_FAILED数据脱敏失败脱敏过程异常检查日志获取详情
INVALID_SANITIZATION_RULE无效的脱敏规则规则配置错误检查规则配置
CONTENT_PROCESSING_FAILED内容处理失败内容格式不支持检查内容类型

⚠️ RULE_COMPILATION_FAILED 与上节的三个授权码同类:曾在 SanitizationException 里声明、 全仓没有发出点(工厂方法只被单元测试调用)⇒ 已随未接线代码一并删除(#406),本表不列。规则编译失败今天表现为 SANITIZATION_FAILED 或 INVALID_SANITIZATION_RULE。 上一版列过的 CONFIGURATION_ERROR / DATABASE_ERROR / CACHE_ERROR 同样全库无匹配:配置、数据库、 缓存故障都表现为 INTERNAL_ERROR(也是解析器对任何不匹配规则的码的兜底值)。


服务不可用 (Service Unavailable)

HTTP 状态码: 503 Service Unavailable

错误码描述常见原因解决方案
SERVICE_NOT_AVAILABLE服务不可用依赖的持久化/清理服务未启用检查服务端配置并等待恢复

下游服务错误码 (Downstream)

HTTP 状态码: 原样取下游返回的状态(常见 502/503/504;下游返回 401 时归一到 401 认证分支)

错误码描述常见原因解决方案
DOWNSTREAM_SERVICE_ERROR下游服务异常上游模型服务报错或超时检查下游服务状态与网络

这个码的 HTTP 状态不固定:SecurityExceptionHandler 直写错误体时原样取下游返回的状态码 ⇒ 注册表里它的状态登记为「随上下文」(不是 502/503 之一)。 上一版用 5xx / 502 / 503 / 504 当「错误码模式」列出,那既不是码也不是本网关发出的值。


错误处理最佳实践

1. 客户端错误处理

// JavaScript 示例
async function handleApiResponse(response) {
  const data = await response.json();

  if (!data.success) {
    const code = data.errorCode ?? data.error?.code;

    switch (code) {
      case 'INVALID_API_KEY':
      case 'EXPIRED_API_KEY':
      case 'EMPTY_API_KEY':
      case 'JWT_EXPIRED':
      case 'JWT_INVALID':
      case 'JWT_BLACKLISTED':
        // 需要重新认证
        window.location.href = '/login';
        break;
      case 'RATE_LIMIT_EXCEEDED':
        // 退避后重试(管理面 429 会带 Retry-After)
        await sleep((Number(response.headers.get('Retry-After')) || 1) * 1000);
        return retryRequest();
      default:
        showError(data.message ?? data.error?.message);
    }
    return;
  }

  return data.data;
}

2. 服务端错误处理

// Java 示例
@RestControllerAdvice
public class ErrorHandler {

    @ExceptionHandler(AuthenticationException.class)
    public ResponseEntity<ErrorResponse> handleAuthException(AuthenticationException ex) {
        // 状态码取异常携带的值(注册表里的认证链路径)
        return ResponseEntity.status(ex.getHttpStatus())
            .body(new ErrorResponse(ex.getMessage(), ex.getErrorCode()));
    }

    @ExceptionHandler(ApiException.class)
    public ResponseEntity<ErrorResponse> handleApiException(ApiException ex) {
        return ResponseEntity.status(ex.getStatus())
            .body(new ErrorResponse(ex.getMessage(), ex.getErrorCode()));
    }
}

3. 错误日志记录

// 记录错误日志
log.error("认证失败: errorCode={}, message={}",
    ex.getErrorCode(), ex.getMessage());

变更记录

版本日期变更内容
1.1.02026-10-15按错误码注册表(ErrorCode,62 个会发出的码)重写:补齐 33 个漏列码、删除 7 个发不出的历史码、标注渲染路径与两处「端点实测状态 ≠ 规则链推导值」、登记 DOWNSTREAM_SERVICE_ERROR
1.0.32026-09-15按代码重写两张表(issue #342/#348):删 17 个不存在的码,补认证链实际发出的码
1.0.12026-06-29更新版本引用为 v2.7.5+,修正版本号错误
1.0.02026-05-25初始版本,包含所有错误码定义

最后更新: 2026-10-15