Skip to content

08. 错误代码 ​

翻译说明: 本页是与 英文源规格 一一对应的机器辅助翻译。代码、协议字段和标识符保持原文;如翻译与英文源事实有歧义,以英文版本为准。

事实来源:packages/shared/src/errors.ts (ErrorCodes)。代码在 §3.7 被保留(在发布之前记录);其他一切都是实时的。

1. Goal ​

提供一种稳定的错误词汇表:

  • Renderer 用户界面
  • Electron IPC
  • Rust 主机 RPC
  • Node pi sidecar 桥

2. 错误对象 ​

ts
type AppError = {
  code: string            // stable machine code, e.g. TOOL_DENIED
  message: string         // English UI/default message
  details?: unknown
  retriable?: boolean
  source?: "renderer" | "electron" | "host" | "agent" | "plugin"
  causeCode?: string      // nested/transport code if mapped
  traceId?: string
}

规则:

  1. code 一旦发布就不可更改
  2. message 为英文源文本(i18n 键可单独映射)
  3. UI 应该更喜欢从 code 派生的 i18n 密钥(如果可用)

桌面测试套件(apps/desktop/test/error-code-registry.test.mjs)会验证 ErrorCodes 的每一项都出现在本文档中,并且 host-core 从其 RPC 调度器和原生 工具发出的每一个 errorCode 都已注册;§3.7 中的保留代码在有实现发出它们 之前,刻意不出现在 ErrorCodes 里。

3. 代码注册 ​

3. 1 应用程序/协议 ​

代码可重审的意义
PROTOCOL_MISMATCH不handshake/protocol 版本不匹配
HOST_UNAVAILABLE是的Rust 主机不是 running/reachable
HOST_OVERLOADED是的绑定主机 RPC/tool 容量已满;背压后重试
AGENT_UNAVAILABLE是的pi sidecar 不是 running/reachable
APP_DEGRADED是的应用程序以有限的功能运行
INTERNAL也许意外的内部故障
INVALID_ARGUMENT不请求 schema/args 无效,包括错误 file/directory 类型的本机工具路径
INVALID_PARAMS不host-core RPC 参数校验失败(数字码 1002);sidecar 和渲染器原样透传
UNAUTHORIZED不capability/auth 边界拒绝呼叫
NOT_FOUND不未找到实体
SESSION_NOT_FOUND不会话作用域的 RPC(包括 tools.execute)点名了主机没有的会话;未知 id 永远不会继承全局工作区
CONFLICT也许状态冲突/资源繁忙
UNSUPPORTED不该操作在此界面上没有实现,例如没有桌面窗口时的受信任扩展提示(规格 16 §9)
FORBIDDEN不RACP:主体的角色不允许该方法(规格 19 §13)
METHOD_NOT_FOUND不RACP:此 Host 上未知的方法,例如没有 Gateway 时的 host/list
IDEMPOTENCY_CONFLICT不队列或回合的幂等 key 以不同输入被重用(D386)
CURSOR_EXPIRED不RACP:回放游标早于保留窗口;从快照重新订阅
CLIENT_TOO_SLOW是的RACP:客户端落后于事件流并被断开
APPROVAL_EXPIRED不RACP:审批期限在回答到达前已过
APPROVAL_STALE不RACP:审批已被处理或属于更早的回合
PAYLOAD_TOO_LARGE不RACP:帧超过协商的大小上限
TIMEOUT是的通用超时
NETWORK_POLICY_BLOCKED不主进程公网策略守卫拒绝了一次抓取,因为它判定了目标:URL 未通过公网 HTTPS 语法检查,或本地 DNS 解析返回了策略判定为非公网的地址——其中包括本地代理生成的 fake-IP 占位地址(ADR 0243)。仅桌面端使用;拒绝即判定,因此在地址改变前重试不会成功。本地解析完全没有返回答案时改用 NETWORK_RESOLVE_FAILED(issue #419)。自 ADR 0304 起,用户自己填写的端点可以解析到本机回环或局域网地址,因此该错误码现在只针对两类首跳:命中完全无服务语义的地址类别(云元数据、unspecified、multicast、reserved),或第三方跳——重定向目标、目录正文、registry 记录。
NETWORK_RESOLVE_FAILED是的主进程公网策略守卫无法判定目标主机:本地 DNS 解析没有返回答案,或在返回前抛错。请求仍与策略拒绝一样被拒,但没有判定任何地址,因此任何界面或日志都不得把它描述成地址校验的判定结果。与 NETWORK_ERROR 不同,后者是请求本身的失败。可重试:当解析器或代理开始应答同一主机时,同一请求即可成功(ADR 0243,issue #419)。
HOST_SHUTTING_DOWN是的主机收到 EOF 正在排空;调用被拒绝而不是被启动
RATE_LIMITED是的某个按调用方计的主机预算(插件会话导入、批量操作)在其窗口内被超出
LIMIT_EXCEEDED不载荷超过了固定的主机上限(条目数、字节数)并被拒绝
CONFIG_SYNC_INVALID不同步配置、密码、路径、请求或审批输入无效
CONFIG_SYNC_LOCKED不本地加密同步 vault 尚未解锁
CONFIG_SYNC_UNSUPPORTED不vault 格式或 WebDAV 服务器能力不受支持
CONFIG_SYNC_REMOTE也许远端 WebDAV 对象、认证、配额或可用性失败
CONFIG_SYNC_CONFLICT也许远端 head、vault 身份或审批 digest 冲突
CONFIG_SYNC_CRYPTO不认证加密、对象身份或密文校验失败
CONFIG_SYNC_MAPPING_REQUIRED不导入的项目作用域配置需要明确的本地文件夹/项目组映射
CONFIG_SYNC_LIMIT_EXCEEDED不加密同步状态超过实体、对象、资源、归档或解压上限

HOST_UNAVAILABLE 是为丢失或损坏的主机 process/transport 保留的, 不是普通的入学压力。 RPC 容量返回 HOST_OVERLOADED,并且 由于操作系统暂时无法启动而无法启动的 shell 进程资源返回 PROCESS_RESOURCE_EXHAUSTED。主机核的控制 stdio 与 Tokio 的动态阻塞池隔离,因此后一种情况 不会将临时线程压力转变为主机进程退出。

3. 2 Agent/会话 ​

代码可重审的意义
AGENT_BUSY不会话已经有活动轮次;父级终态错误后的残留子智能体不会让会话保持忙碌(D352)
AGENT_NOT_FOUND不会话丢失
TURN_NOT_FOUND不使 id 无效
TURN_ABORTED不回合被 user/system 中止
MODEL_NOT_CONFIGURED不未选择可用模型,或提供商因未知而拒绝所选模型
PROVIDER_ERROR是的上游提供商故障;可重试的故障(5xx 网关)最多获得四次同回合重试,格式错误的 400/422 请求是终止的
PROVIDER_UNAUTHORIZED不bad/missing 提供商凭证
PROVIDER_RATE_LIMITED是的供应商费率有限
CONTEXT_TOO_LARGE不恢复后 prompt/context 仍超出安全模型预算、发生第二个提供程序溢出或禁用自动恢复
CONTEXT_COMPACTION_FAILED不自动保留尾部恢复无法准备、持久或适合检查点,或手动检查点摘要生成/持久追加失败;受保护的下一个提供程序请求不会启动
STREAM_FAILED是的提供程序流在完整响应之前终止、提前关闭或以其他方式结束;最多四次同回合重试可能会在终止事件之前发生
EMPTY_MODEL_RESPONSE是的模型在没有工具调用且没有可见文本的情况下结束了两次:一次是流式传输,一次是在自动重新运行后;对 Host 账本完成通知的第一条回复除外(规范 02-agent-runtime §5e、D446)
PROMPT_ENHANCEMENT_EMPTY不一次性增强模型没有返回任何文本
SPEECH_NOT_CONFIGURED不设置里没有绑定转写或朗读
SPEECH_PROTOCOL_UNSUPPORTED不语音协议未知或不支持该角色
SPEECH_INPUT_TOO_LARGE不语音输入超过 25 MB
SUBAGENT_IDLE_TIMEOUT不已撤回(D328):空闲看门狗不再武装;代码仅为已存储结果保留
SUBAGENT_DURATION_TIMEOUT不已撤回(D328):时长看门狗不再武装;代码仅为已存储结果保留
SUBAGENT_CONTEXT_OVERFLOW不委派自身的模型上下文超出其安全预算,自动的回合边界压缩与仅保留任务简报和最近消息的降级重试都没能把它带回限制以内;该失败给出可执行的恢复方式,而不是提供商的溢出文本

3. 3 工作空间/工具/权限 ​

代码可重审的意义
WORKSPACE_REQUIRED不无工作空间限制
PATH_OUTSIDE_WORKSPACE不在显式外部路径权限决策之前路径逃逸沙箱,或提示词附件位于其会话 scratch/project/attachment 根目录之外
WORKSPACE_PATH_DENIED不显式的 Read/Write/Edit 路径命中了始终开启的安全拒绝名单(私钥、.env 文件、凭证包、.git/objects);外部路径授权不会解除它(规格 15 §3)
READ_PATH_IS_DIRECTORY不Read 拿到的是目录;结果附带一条 Glob 建议
TOOL_BINARY_CONTENT不Read 拒绝把二进制文件倾倒进模型上下文
TOOL_NOT_FOUND不未知工具
TOOL_DENIED不权限被拒绝/模式被禁止
TOOL_TIMEOUT是的工具执行超时
TOOL_FAILED也许工具已执行但失败
TOOL_ABORTED不工具在完成前被用户停止或回合中止取消
MUTATION_RETRY_BUDGET_EXHAUSTED是重复保护在同路径 Edit 或 shell patch 反复失败后终止了本轮;携带 details.kind(edit 或 patch-command)与最后一个工具错误代码
PROCESS_RESOURCE_EXHAUSTED是的shell 进程无法启动,因为操作系统暂时耗尽了进程资源
SHELL_NOT_FOUND不目录回退后没有有效的平台 shell 可用;消息承载指引
COMMAND_SHELL_CHANGED不固定的 shell ID 或方言在执行前已更改
COMMAND_SHELL_INVALID不设置提供了未知、不可用或错误的平台 shell ID
PERMISSION_TIMEOUT不权限提示超时(映射为拒绝)
PERMISSION_REQUIRED不等待用户决定
WRITE_DISABLED_IN_PLAN不Write 的契约模式硬拒绝
EDIT_DISABLED_IN_PLAN不编辑的契约模式硬拒绝
PLUGIN_DISABLED_IN_PLAN不每个插件工具的契约模式硬拒绝
TOOL_DISABLED_IN_PLAN不unknown/unlisted 工具的契约模式硬拒绝
PLAN_NOT_ACTIVE不在没有协商合同的情况下运行了提交工具
PLAN_KIND_MISMATCH不Goal 模式下的 SubmitPlan,或 Plan 模式下的 SubmitGoal
PLAN_APPROVAL_REQUIRED不SubmitPlan/SubmitGoal 正在等待单独的批准
PLAN_APPROVAL_TIMEOUT不绝对 30 分钟计划批准期限已过
PLAN_APPROVAL_STALE不响应与实时 proposal/session/turn/tool-call/version 不匹配
PLAN_APPROVAL_INTERRUPTED不待批准在中止、崩溃或持久性失败期间关闭
PLAN_ARTIFACT_WRITE_FAILED不主机无法将确切的字节写入新的 .pi/<kind>/*.md 工件
PLAN_EXECUTION_INTERRUPTED不已批准的 queued/running Plan 或 Goal 执行已停止且不重播
PLAN_REQUIRES_INTERACTIVE_SESSION不unattended/scheduled Plan 或 Goal 运行无法请求批准
PLAN_NOT_FOUND不没有审批记录与该提案 id 匹配
PLAN_SESSION_NOT_FOUND不Plan/Goal RPC 点名了主机没有的会话
PLAN_WORKSPACE_REQUIRED不会话没有持久化的项目;临时会话无法进入 Plan 或 Goal
PLAN_ALREADY_ACTIVE不会话已经有一份正在协商的契约
PLAN_ALREADY_PENDING不同一回合的审批仍在等待时又收到了一次提交
PLAN_ALREADY_RESOLVED不第二次 approve/reject 到达了一个已经裁决的审批
PLAN_APPROVAL_CONFLICT不审批记录在版本守卫更新底下被改动
PLAN_INVALID_ACTION不审批响应既不是 approve 也不是 reject
PLAN_INVALID_ARGUMENT不submit/resolve 参数校验失败
PLAN_PERMISSION_MODE_REQUIRED不approve 没有选择 ask、accept-edits 或 auto
PLAN_PERMISSION_MODE_INVALID不选定的权限模式不是这三者之一
PLAN_MARKDOWN_TOO_LARGE不提交的 Markdown 超出工件大小上限
PLAN_REJECTED不用户拒绝了提案;本轮结束且不执行
PLAN_SUBMIT_FAILED也许主机无法记录提案
PLAN_CONFIGURATION_BLOCKED不提案或执行进行中时 session.configure 被拒绝
PLAN_ARTIFACT_INVALID不检查点工件在执行前未通过校验
PLAN_ARTIFACT_NOT_READY不工件尚未持久写入就被认领执行
PLAN_ARTIFACT_PATH_UNSAFE不工件路径逃逸了 <workspaceRoot>/.pi/<kind>/
PLAN_ARTIFACT_COLLISION_LIMIT不主机用尽了唯一的工件名
PLAN_ARTIFACT_HASH_MISMATCH不执行时工件字节与记录的哈希不再一致
PLAN_EXECUTION_ACTIVE不该会话已有一个已批准的执行在运行
PLAN_EXECUTION_NOT_FOUND不没有排队中的执行与认领匹配
PLAN_EXECUTION_ALREADY_CLAIMED不另一个认领者抢先拿走了排队中的执行
PLAN_EXECUTION_STALE不执行 epoch 与当前会话不再匹配
PLAN_EXECUTION_STATUS_INVALID不当前状态不允许该状态迁移
PLAN_EXECUTION_CONFLICT不执行记录在版本守卫更新底下被改动
PLAN_EXECUTION_FAILED也许已批准的执行以错误结束
PLAN_INTERNAL也许没有更细分类的 Plan/Goal 主机失败
WRITE_DISABLED_IN_CHAT不历史遗留(D188 之前的 Chat profile);为已存储的转录本保留注册,不再发出
BASH_DISABLED_IN_CHAT不历史遗留(D188 之前的 Chat profile);为已存储的转录本保留注册,不再发出

_IN_PLAN 后缀和 PLAN_ 前缀是历史性的:两种合约模式 (Plan 和 Goal)共享这些代码,而不是复制 _IN_GOAL 集 (D198)。渲染器从提案的 kind 中选择其措辞,因此 代码可以显示为“Plan”或“Goal”副本。

3. 4 Edit 契约(ADR 0087) ​

仅由 Edit 发出。版本与来源失败拥有各自的代码,因为每一个都指向不同的 下一步动作;把它们报告为 TOOL_FAILED 会丢失这一信息。见 18-line-anchored-edit-contract §11。

代码可重试含义
EDIT_TAG_REQUIRED否tag 缺失或不是 4 位十六进制
EDIT_TAG_MISMATCHRead 之后可以tag 无法哈希出实时文件且漂移恢复拒绝;携带实时 tag 与锚点处的当前内容
EDIT_TAG_UNKNOWNRead 之后可以tag 格式正确,但本会话没有为该路径记录过对应内容
EDIT_LINES_UNSEEN是锚点引用了会话从未显示过的行;携带被揭示的内容
EDIT_PARSE_FAILED否操作头格式错误、无冒号头下出现正文行、缺少正文,或出现 -/上下文行
EDIT_RANGE_INVALID否范围反向、行号越界、操作重叠,或锚点重复
EDIT_BLOCK_UNRESOLVED否N* 定位符无法解析;消息给出纯范围替代方案
EDIT_REGISTER_EMPTY否从未设置的寄存器粘贴
EDIT_REGISTER_AMBIGUOUS否存在多个待粘贴的匿名捕获时进行匿名粘贴
EDIT_REPAIR_AMBIGUOUS否边界修复候选在最小代价上并列
EDIT_NO_CHANGE否应用产生了与输入完全相同的文本
EDIT_AMPLIFICATION_LIMIT否下降展开超过膨胀上限

当消息报告 reveal 完整时,EDIT_LINES_UNSEEN 无需再次 Read 即可重试: 被揭示的行已并入会话来源集,因此原样重试同一个 tag 即可应用。被截断的 reveal 不并入任何行,必须重新读取。

EDIT_TAG_MISMATCH、EDIT_TAG_UNKNOWN 与 EDIT_LINES_UNSEEN 在重复保护开始计数 之前,各自在每条路径上有一次免费尝试,因为每一个都已经携带了重试所需的东西。其余代码 在第一次出现时就计数,而耗尽额度的那次失败会以 §3.3 的 MUTATION_RETRY_BUDGET_EXHAUSTED 出现在 assistant 行上 (18-line-anchored-edit-contract §9.3)。

3. 5 秘密/设置 ​

代码可重审的意义
PROVIDER_SECRET_MISSING不启用的提供程序需要 API 密钥
MODEL_ALIAS_TOO_LONG不已配置模型别名超过 60 个 Unicode 字符
MODEL_BINDINGS_DEGRADED不存储模型绑定已降级;为防止数据丢失,拒绝显式替换模型数组
SECRET_STORE_UNAVAILABLE也许操作系统安全存储不可用(保留)
SETTINGS_INVALID不设置有效负载无效(保留)

3. 6 插件 ​

代码可重审的意义
PLUGIN_NOT_FOUND不插件 ID 缺失
PLUGIN_INVALID不manifest/package 无效
PLUGIN_LOAD_FAILED也许enable/load 失败
PLUGIN_DISABLED不插件已禁用(保留)
PLUGIN_PERMISSION_DENIED不插件缺少该调用所需的已声明且已授予的权限
PLUGIN_INTEGRITY不包校验和或签名与目录条目不匹配
PLUGIN_NETWORK是的市场下载或目录拉取失败
PLUGIN_HOST_TOO_OLD不包的 engines.piDesktop 范围排除了当前宿主
PLUGIN_MARKET_INVALID不市场目录格式错误或缺少必需的发布字段
PLUGIN_MARKET_UNTRUSTED_HOST不目录或包 URL 不在可信市场主机之内
PLUGIN_MARKET_YANKED不请求的发布版本已从目录中撤回
PLUGIN_MARKET_NOT_PUBLISHED不平台有该版本但尚未对外提供
PLUGIN_MARKET_ARCHIVED不插件已被平台下架
PLUGIN_MARKET_NOT_FOUND不平台没有该插件或该版本
PLUGIN_MARKET_RATE_LIMITED是下载接口要求客户端等待后重试
PLUGIN_MARKET_NO_SOURCE也许没有任何分发目标能提供该包
PLUGIN_CANCELLED不用户在下载过程中取消了安装
MCP_INVALID不用户的 MCP 服务器定义校验失败
SKILL_INVALID不用户的技能文档校验失败
SUBAGENT_INVALID不用户的子代理文档校验失败
CAPABILITY_INVALID不Agent 能力根目录或作用域设置校验失败
PLUGIN_COMMAND_NOT_FOUND不命令 ID 丢失(保留)
PLUGIN_CRASHED是的插件运行时崩溃(保留)
PLUGIN_CONTRACT_MISMATCH不不支持的 manifest/api 版本(保留)

3. 7 保留的详细代码(尚未发布) ​

记录了更细粒度的 provider/tool 区别,以供将来映射。 在发布之前,实现使用所示的规范父代码。

保留代码今天的规范父母笔记
PROVIDER_BASE_URL_INVALIDPROVIDER_ERROR端点无效(400)
PROVIDER_PROTOCOL_MISMATCHPROVIDER_ERROR错误的协议配置文件
PROVIDER_MODEL_NOT_FOUNDMODEL_NOT_CONFIGURED未知模型 ID (404)
PROVIDER_TIMEOUTTIMEOUTnetwork/server 超时(可重试)
PROVIDER_UNSUPPORTED_CAPABILITYPROVIDER_ERRORtools/vision 不支持
PROVIDER_DISABLEDMODEL_NOT_CONFIGURED提供商已禁用

WORKSPACE_PATH_DENIED 和 TOOL_BINARY_CONTENT 在主机开始发出它们时已从 本表移出(§3.3)。

历史别名(切勿在新代码中使用):PROVIDER_AUTH_FAILED → PROVIDER_UNAUTHORIZED; PROVIDER_STREAM_INTERRUPTED → STREAM_FAILED; WORKSPACE_OUTSIDE_ROOT → PATH_OUTSIDE_WORKSPACE; SECRET_MISSING → PROVIDER_SECRET_MISSING; SHELL_UNAVAILABLE → SHELL_NOT_FOUND; SHELL_IDENTITY_STALE → COMMAND_SHELL_CHANGED; PLAN_APPROVAL_EXPIRED → PLAN_APPROVAL_TIMEOUT。截断不是错误:有界工具结果 带有一个标记,命名哪一端幸存以及其余部分在哪里,或者报告 同级结果字段中的有界窗口 (请参阅 16-工具-结果-限制)。

3.8 远程控制(RACP-WS / SSH 引导) ​

当会话位于经 RACP-WS 驱动的已配对远程主机上时,由桌面端的远程主机客户端与 pi-host 服务端发出(参见 19-远程代理控制协议、 ../05-security/02-remote-control-security、 ADR 0285)。渲染进程除了一个标识徽章外看不到本地/远程之分;这些码通过与其他调用 相同的错误对象浮现。

码可重试含义
HOST_DISCONNECTED是远程主机连接断开;进行中的调用被拒绝,客户端按游标重连并重新订阅
HOST_BOOTSTRAP_FAILED否经 SSH 配置远程 pi-host 失败(下载、校验和不匹配或 install.sh);details.reason 指明阶段
HOST_VERSION_MISMATCH否远程 pi-host 版本与桌面不匹配;桌面拒绝驱动不兼容的主机
REMOTE_AUTH_FAILED否设备或配对令牌在 RACP-WS 升级时被拒
REMOTE_CONNECTION_FAILED是RACP-WS 传输无法连接(非回环 URL、套接字被拒)
REMOTE_FORWARD_FAILED是无法建立 SSH 回环端口转发
REMOTE_PATH_NOT_FOUND否远程项目/工作区路径在主机上不存在
REMOTE_PATH_FORBIDDEN否远程路径在主机允许的根之外
PAIRING_FAILED否connection/pair 无法铸造设备凭据
PAIRING_TOKEN_EXPIRED否一次性配对令牌在配对完成前已过期
CAPABILITY_UNAVAILABLE否请求的操作对应主机声明为不可用的能力(如附件、工具中继)

4. 映射规则 ​

主机 RPC 数字 → AppError.code ​

请参阅 06-host-rpc-protocol.md 数值表。 示例:主机 1004 → TOOL_DENIED。

提供商例外 ​

Node sidecar 将提供商 SDK 错误映射到:

  • PROVIDER_UNAUTHORIZED
  • PROVIDER_RATE_LIMITED
  • MODEL_NOT_CONFIGURED(提供商拒绝选择的模型并返回 404)
  • PROVIDER_ERROR
  • NETWORK_ERROR
  • STREAM_FAILED

精确的 terminated 提供商消息和等效的过早流关闭 消息映射到 STREAM_FAILED。请求设置阶段或响应后的 PROVIDER_RATE_LIMITED 使用共享的运行时预算:初始尝试之后最多 10 次重试, 且设置和流式传输失败一起计数。非 429 瞬时故障——STREAM_FAILED、 NETWORK_ERROR、TIMEOUT 以及可重试的 PROVIDER_ERROR(例如上游网关 502/503/504)——共享它们自己的有界预算:初始尝试之后最多 10 次重试,同样 跨请求设置和流式传输一起计数,并且与 429 预算相互独立。两个预算都是 可中止的。429 路径在客户端退避之前先遵循 retry-after-ms、retry-after 秒和 HTTP 日期标头,并将等待上限设为 30 秒;非 429 路径应用相同的优先级, 上限为 8 秒,在其他情况下依次等待 1 秒、2 秒、4 秒,然后是 8 秒。只有失败 的请求会被重放;会话及其工具状态保持不变。来自格式错误的 400/422 请求的 不可重试 PROVIDER_ERROR 永远不会进入任何预算。预算耗尽后的失败仍然是 致命的。设置 infiniteProviderRetry 默认关闭;开启后只移除上述可重试网络/瞬时类别的次数上限, 不会改变退避、Retry-After、取消或终止分类,并可能在用户停止回合前持续消耗 API 用量。

Synchronized update (#699): A complete successful model response resets both budgets, including a tool-call response, in the main session and builtin subagents. Headers, partial output, and phase changes do not replenish them. Exhaustion reports retryAttempt: 10 from the relevant budget counter.

NETWORK_ERROR 以有界的 details 携带真正失败的传输层: networkCategory(dns、tls、timeout、refused、unreachable、 reset、proxy,或在没有留下任何线索时为 unknown)、networkCode (errno,例如 ENOTFOUND、ECONNRESET、EPROTO、UND_ERR_SOCKET), 以及传输层提供时的 networkSyscall 和 networkHost。只保留裸主机名—— 绝不包含 URL、端口、路径、查询串或凭据——当 providerCode 会重复 networkCode 时省略它。刻意不引入按层划分的错误码(DNS_ERROR、 TLS_ERROR、SOCKET_RESET 等):分类字段已能区分这些层,而无需为每一层 增加用户可见的错误码与本地化文案。

诊断来自 fetch 边界处的实时 cause 链,而不只是提供程序消息:pi-ai 会把被 拒绝的请求摊平成 errorMessage,等到分类运行时 undici 存放在 error.cause 里的 errno 已经消失,裸 fetch failed 只能被记为 networkCategory: unknown; 而 fetch 包装层仍持有原始 Error,并从它给出同一组经过校验的字段。捕获到的 cause 同时确定了阶段:没有任何响应到达时故障记为 phase: request,这正是它 与「响应中途断流」的区别。networkRoute(direct、environment-proxy、 http-proxy、socks5-proxy)指出请求实际走的链路,代理这一跳失败无需再从 errno 猜测。

同一来源在一轮内连续两次这样失败(完全没有响应)时,下一次尝试前会重建提供 程序传输,而不是继续复用同一个 undici 连接池。重建是进程级的、且有明确边界: 每个连续失败序列只重建一次,每 30 秒最多一次,且 dns 永不触发重建(新连接池 无法改变名字解析结果)。替换在关闭旧 dispatcher 之前安装,旧的 dispatcher 采 用优雅关闭,因此其他会话已派发的请求仍会在它原本使用的连接池上完成。生效的 链路会被原样复现,绝不会悄悄降级为直连。

权限超时 ​

UI/host 超时在内部发出 PERMISSION_TIMEOUT,工具结果向代理显示为拒绝 (TOOL_DENIED)。

Shell 和 Plan/Goal 检查点失败 ​

仅当目录回退发现不可用时才返回 SHELL_NOT_FOUND 平台外壳。 COMMAND_SHELL_CHANGED 永远不会使用不同的 shell 重试; 该回合必须获得新的有效 ID/dialect。 PLAN_ARTIFACT_WRITE_FAILED 从不创建批准行。 PLAN_APPROVAL_TIMEOUT 仅适用于 绝对待决期限; PLAN_EXECUTION_INTERRUPTED 标识已批准的 queued/running 执行因中止或主机恢复而中断。 PLAN_KIND_MISMATCH 是 终止工具错误,如 PLAN_NOT_ACTIVE:提交工具运行于 错误的合同,因此没有编写任何工件,也没有创建批准行。

5. UI 处理指南 ​

类用户界面行为
auth/config(PROVIDER_SECRET_MISSING、MODEL_NOT_CONFIGURED)带有设置 CTA 的助理错误消息
拒绝许可内联工具卡状态
可重试的 provider/network带有重试操作的助理错误消息
internal/host 不可用降级横幅 + 恢复提示

消息绑定提供程序故障从不使用 toast 或浮动全局横幅。 助手错误消息显示本地化摘要和稳定代码,并带有 包含经过编辑的提供商响应的可访问详细信息披露, 提供商 ID 和模型 ID。提供商详细信息上限为 600 个字符,并且 公共 credential/header 值在事件发射或持久化之前进行编辑。 详细信息披露也可能显示有界的 phase、providerStatus、providerCode、 providerWaitMs、streamMs、retryAttempt、networkCategory、 networkCode、networkSyscall、networkHost、networkRoute、requestMessages、 requestBytes 和 compactionGeneration 字段。请求字段只有计数与字节大小, 压缩字段是检查点世代计数器,均不携带消息内容。当瞬时提供商故障正在重试时, 活动指示器的原因气泡会显示本地化摘要、稳定错误码,并在网络故障时显示传输层 errno(NETWORK_ERROR · ENOTFOUND),因此失败层级在重试期间与日志记录中 同样可见。

6. i18n 按键约定 ​

text
errors.<code>
errors.<code>.action

示例:

  • errors.PROVIDER_SECRET_MISSING
  • errors.PROVIDER_SECRET_MISSING.action
  • errors.HOST_UNAVAILABLE

7. 验收 ​

  1. 每次 IPC 失败都会返回 AppError.code
  2. 主路径上没有原始非类型化字符串故障
  3. Plan/Goal 硬否认使用显式特定于工具的代码; Bash 从未被否认 仅仅因为运营模式而采用任一合同模式,而不是 遵循权限策略
  4. 主机数字代码映射到稳定的字符串代码
  5. 无效的 shell 设置、no-effective-shell/stale-pin、artifact-write、 到期、计划拒绝和重新启动中断路径映射到稳定 代码;仅允许记录的预转目录后备,并且不进行任何工作 正在重播

证书校验失败(issue #714) ​

当 details.networkCode 是已识别的证书校验错误时,NETWORK_ERROR 不可重试, 包括不受信任或自签名链、证书已过期或尚未生效,以及 ERR_TLS_CERT_ALTNAME_INVALID。具体证书原因优先于通用 socket/proxy 包装错误。 即使 adapter 已将错误扁平化,捕获的 fetch 原因仍会应用这条策略。未知 TLS 错误和 非证书协议错误继续使用原有恢复行为。

transcript 保留稳定错误码、传输 errno 和原始 details,但使用本地化的证书指引, 而不是通用连接错误摘要。它会提示用户检查证书、系统时间以及安全软件或代理使用的 信任根,并在修改信任设置后重启。文案不会断言一定是流量拦截,也不会提供关闭 TLS 校验的绕过方式。修复原因后,用户仍可手动继续。

本地请求准备错误 ​

上下文校验、估算或请求准备阶段产生的结构化 LOCAL_REQUEST_ERROR,映射为既有 INTERNAL 且 retriable: false。在适配器把异常压成文字前保留本地来源与阶段; 诊断可以保留原因类型,不向界面复制请求正文、搜索结果、凭据或任意底层异常文字。 不能靠匹配异常句子或统一禁用所有 TypeError 重试来分类;网络故障和取消维持原有策略。

历史恢复校验可能在运行时流创建前失败。此时使用既有 RPC 错误 data,携带 errorCode、retriable: false 及安全的 details(来源、阶段、可选原因类型)。 不得发出模型请求,sidecar 保持可用,也不改写存储记录;容器不是存储块列表时仍按此失败。

单个存储块无法回放属于另一种情况:网关丢弃 id 时本应用本身就会存下仅供展示的块, 因此该消息的整条 replay 降级为“没有 replay”,而不是让之后每一轮请求都失败。 回合继续执行,展示轮次不变;诊断只记录块数与阶段,不复制搜索内容、结果或凭据。

本地优先 · 模型可替换 · 插件可扩展。 AIUO.NET