Skip to content

错误码参考 ​

本文档汇总 Shield runtime error 的稳定错误码,是错误码的权威来源。业务错误不由本文档统一分配。

实现快照:以下错误码中,标记为『已实现』的已在代码中使用并有测试覆盖;标记为『部分』的在代码中使用但错误码字符串可能不完全匹配;标记为『未实现』的属于 Phase 2+,当前未实现。

错误对象结构 ​

所有 runtime 错误通过 ok == false 返回,第二个返回值是 Error 对象:

lua
{
  code = "timeout",           -- 错误码(本文档定义)
  message = "call timeout",   -- 人类可读描述
  retryable = true,           -- 是否建议重试(timeout=true,其他=false)
  -- 以下字段属于 Phase 2 扩展,当前未填充:
  -- source = "runtime",      -- 来源:runtime | data | network
  -- detail = nil,            -- 可选调试信息
}

规则:

  • 本文档只定义 runtime/framework 错误。
  • shield.call 成功返回时,后续返回值全部属于 callee 的业务契约,不由 runtime 解释。
  • 旧 API 删除后的报错也使用本文档中的稳定错误码。

一、消息与服务错误 ​

shield.send / shield.call / shield.spawn 产生的错误。

错误码来源说明retryable状态
invalid_targetsend/call目标格式错误(非 handle 且非合法 name)否已实现
invalid_methodsend/call方法名非法(空、过长、含非法字符)否已实现 send 检查空/超长/on_ 前缀
invalid_service_modulespawnLua 文件未返回合法 service module table否已实现
script_load_failedspawnLua 文件语法错误、load 失败或顶层代码抛错否已实现
invalid_namespawn服务名不合法(格式、长度、保留前缀)否部分 当前统一返回 spawn_failed
name_conflictspawn服务名已被占用否部分 当前统一返回 spawn_failed
encode_failedsend/call消息编码失败(类型不支持、嵌套过深、循环引用)否已实现 send 检测 unsupported 类型
message_too_largesend/call消息体积超过 max_message_size(默认 1MB)否已实现 send 检查
service_not_foundsend/call目标服务不存在(name 未注册或 handle 已失效)是已实现 send 和 call 均返回
service_deadsend/call目标服务已停止否已实现 send/call 区分 service_not_found 和 service_dead
node_offlinesend/call目标节点离线(集群场景)是已实现 ClusterManager.check_node_reachable 返回 offline/suspect/removed
init_failedspawnon_init 返回失败或抛出异常否已实现 spawn 返回 init_failed 错误码
spawn_timeoutspawn服务初始化超过 spawn_timeout(默认 10s)否已实现 on_init 超时检测
runtime_stoppingsend/call/spawn运行时正在关闭否已实现 send/call/spawn 检查
permission_deniedsend/call/spawn权限不足否已实现 permission_check 钩子
spawn_failedspawn其他未分类 spawn 失败(含当前 name 冲突/非法名的返回码)否已实现 spawn 默认错误码
register_failedregister发布本地 name 失败(name 冲突或非法)否已实现 register 返回
unregister_failedunregister注销本地 name 失败否已实现 unregister 返回
claim_failedclaim蓝绿交接接管 name 失败(name 不存在/非法、无调度上下文)否已实现 claim 返回
timeoutcall调用超时(默认 5s)是已实现
method_not_foundcall目标服务没有该方法否已实现
handler_errorcall目标服务 method 抛出未捕获异常否已实现 call 返回
context_expiredcontexthandler 已返回,shield.sender/trace/deadline 上下文失效否已实现 当前返回 nil(设计决策:handler 外读取 sender 返回 nil,不抛错)
api_not_allowed_in_exitexit hook在 on_exit 中调用了会挂起的 API否已实现
legacy_api_removedlegacy API调用了已删除的旧 API否已实现

二、资源限制错误 ​

服务级资源超限产生的错误。

错误码说明默认上限状态
coroutine_limit单个 service coroutine 数超限1000已实现 call_service_method_coroutine 检查
pending_call_limit单个 service 待响应 call 数超限1000已实现 suspend_for_call 检查
timer_limit单个 service timer 数超限10000已实现 timer_once/timer 返回 nil+error
timer_not_foundcancel_timer 目标不存在或已完成—已实现 cancel_timer 返回 false+error
fork_limit单个 service fork task 数超限1000已实现 fork 返回 nil+error

三、数据插件错误 ​

数据插件 namespace(如 shield.database.mysql(...)、shield.database.mongodb(...))产生的错误。连接池和驱动归插件 instance 自治。

错误码说明retryable状态
module_unavailable对应插件、binding 或 instance 不可用否已实现
database_error未分类的数据库执行失败视具体驱动已实现 (代码中使用 database_error)
db_query_failed未分类的数据库执行失败视具体驱动已实现 DB query/execute 返回
connection_lost数据库连接丢失是已实现 MySQL error msg 映射
connection_timeout建立连接超时是已实现 MySQL timeout msg 映射
query_timeout查询超时是已实现 由 connection_timeout 覆盖(同一异常路径)
syntax_errorSQL 语法错误否已实现 MySQL syntax msg 映射
constraint_violation约束违反(唯一键、外键等)否已实现 MySQL Duplicate/constraint msg 映射
transaction_aborted事务中止是已实现 MySQL Deadlock msg 映射
transaction_closed事务 callback 结束后继续使用 tx 句柄否已实现 Lua transaction guard
pool_exhausted连接池耗尽是已实现 acquire 失败返回
mapper_unsafe_sqlLua mapper 使用 ${} 原样替换或多语句 SQL否已实现 Lua mapper guard
mapper_invalid_statementLua mapper statement 类型不支持否已实现 Lua mapper guard
entity_invalid_rowLua entity helper 缺少可写字段否已实现 Lua entity guard

四、缓存 / 队列 / Redis provider 错误 ​

Redis 系插件 namespace(如 shield.cache.redis(...)、shield.queue.redis(...)、shield.leaderboard.redis(...))或依赖 Redis 的 optional module 产生的错误。

错误码说明retryable状态
module_unavailable对应插件、binding 或 instance 不可用否已实现
redis_error未分类的 Redis 命令失败视具体驱动已实现 (代码中使用 redis_error)
redis_command_failed未分类的 Redis 命令失败视具体驱动已实现 Redis 操作返回
connection_lostRedis 连接丢失是已实现 redis++ ClosedError/IoError 映射
connection_timeout建立连接超时是已实现 redis++ TimeoutError 映射
command_timeout命令执行超时是已实现 redis++ TimeoutError 映射
wrong_typeRedis 类型错误否已实现 redis++ ReplyError(WRONGTYPE) 映射
pool_exhausted连接池耗尽是已实现 acquire 失败返回

五、网络错误 ​

shield_net / session / 客户端 RPC 相关的错误。

错误码说明retryable状态
session_closedsession 已关闭,handle stale否已实现 TcpSession::send/send_message 返回
session_send_queue_fullsession 发送队列已满是已实现 TcpSession::send/send_message 返回
handshake_timeout握手超时否已实现 TcpSession::handle_error 映射
decode_error协议解码错误否已实现 TcpSession::handle_error 映射
protocol_not_configuredsession 未绑定协议管线时收到入站字节(TCP 必须带 network.protocol)否已实现 TcpSession::handle_error 映射
connection_limit连接数达到上限是已实现 TcpListener::do_accept 检查
ip_limit单 IP 连接数达到上限否已实现 TcpListener::do_accept 检查

六、shield_player 错误 ​

shield.player.* 门面与 player 会话状态机产生的错误(runtime-player.md "shield_player 模块契约(P0)")。除 guard 的 not_ready 以 bool + code 返回外, 其余均以 nil + 错误对象 形态返回;guard 拒绝与 gateway 入站校验失败同形态 (丢帧 + warn + 计数,不回写错误帧)。

错误码说明retryable状态
module_unavailableSHIELD_ENABLE_PLAYER 未编译;每个 shield.player.* 入口都返回否已实现 register_player_stub_api
setup_invalidsetup 缺少必填钩子或参数形状非法否已实现 impl.setup 校验
auth_failedauth hook 拒绝,或未产出非空 string player_id否已实现 impl.authenticate 第 1 步
anonymous_disabledauth 结果带 anonymous 但配置未开启否已实现 impl.authenticate 第 2 步
spectator_disabledauth 结果带 spectator 但配置未开启否已实现 impl.authenticate 第 2 步
already_onlinePlayerManager admit:该 uid 已有在线会话(默认单设备踢旧)否已实现 PlayerManager::admit
too_many_devicesmulti 设备策略下超出 player.max_devices否已实现 PlayerManager::admit
instance_script_requiredauthenticate 未配置 opts.instance_script 无法 spawn 实例否已实现 impl.authenticate 第 4 步
invalid_player_refpush/resolve 目标既不是 uid 字符串也不是合法 PlayerRef否已实现 impl.push / resolve
player_not_foundresolve:ref 已失效;push:uid 不由本服务承载否已实现 PlayerManager::get / impl.push
remote_resolve_unimplementedresolve 收到跨节点 ref(P0 仅本地)否已实现 resolve
not_readyclient_message guard:会话未到 ready,消息丢帧 + 计数否已实现 __shield_player_guard
rejectedclient_message 业务 hook 拒绝且未给 code 时的兜底否已实现 __shield_player_guard
offline_queue_full离线队列超过 player.message_queue_limit(默认 64)是已实现 impl.push
push_route_not_foundpush 目标 route 无 s2c helper否已实现 impl.push
persistence_save_failedplayer_save 抛错;按 player.on_save_error 记 warn 或 panic是已实现 defaults.save

七、shield_server 错误 ​

shield.server.* 门面与服务器状态机产生的错误(runtime-server.md)。 除 set_state/shutdown 的参数与状态机错误以 nil + 错误对象 形态返回外, 查询入口恒成功(模块不可用时返回 module_unavailable)。

错误码说明retryable状态
module_unavailableSHIELD_ENABLE_SERVER 未编译或模块未初始化;每个 shield.server.* 入口都返回否已实现 register_server_stub_api
invalid_stateset_state 参数不是 starting/running/maintenance/shutdown 之一否已实现 impl.set_state
invalid_state_transition状态机不允许的迁移(如 starting→maintenance、shutdown 后任何迁移)否已实现 impl.set_state
shutdown_already_scheduledshutdown 重复调用;不重复计时否已实现 impl.shutdown
invalid_argumentshutdown 参数不是 ≥0 的整数否已实现 impl.shutdown

八、错误处理建议 ​

重试策略 ​

lua
function M.call_with_retry(target, method, data, max_retries)
    max_retries = max_retries or 3
    local retries = 0

    while retries < max_retries do
        local ok, result = shield.call(target, method, data)
        if ok then
            return true, result
        end

        if result.retryable then
            retries = retries + 1
            if retries < max_retries then
                shield.sleep(100 * retries)  -- 指数退避
            end
        else
            return false, result
        end
    end

    return false, {
        code = "max_retries_exceeded",
        message = "Max retries exceeded",
        source = "runtime",
        retryable = false,
    }
end

错误日志 ​

lua
-- Runtime 错误
shield.log.error(string.format(
    "[runtime] %s: target=%s method=%s code=%s message=%s",
    "call_failed", target, method, err.code, err.message
))

-- 业务错误
shield.log.warn(string.format(
    "[business] %s: target=%s method=%s code=%s message=%s",
    "business_error", target, method, err.code, err.message
))

业务错误 ​

业务错误属于 callee 自己的返回契约,不使用 ok == false 传递:

lua
-- Callee
function M.get_player(uid)
    local player = find_player(uid)
    if not player then
        return {
            ok = false,
            code = "PLAYER_NOT_FOUND",
            message = "Player not found",
        }
    end

    return {
        ok = true,
        player = player,
    }
end

-- Caller
local ok, result = shield.call("player", "get_player", uid)
if not ok then
    -- Runtime 错误(本文档定义的错误码)
    shield.log.error("runtime error: " .. result.code)
elseif not result.ok then
    -- 业务错误,由业务自己定义
    shield.log.warn("business error: " .. result.code)
else
    process_player(result.player)
end

Apache License 2.0