按观察到的现象或报错原文定位原因与解决办法。
本页按观察到的现象索引。如果已经拿到错误码、异常类名或进程退出码,请直接查阅错误与错误码,该页按错误身份索引。
现象:
排查启动问题时建议捕获
Java 没有 stderr 回调。CLI 非正常退出时,
部分选项会在前置阶段校验,因此拼写错误会立即失败,而非让某项功能被静默关闭。以下异常在 QoderCN CLI 启动之前同步抛出。
Java 的
现象:
现象: 工具已注册、会话正常启动,但 Agent 绕过该工具完成了任务。
按以下顺序排查:
现象: 工具调用被拒绝,或运行停滞在一个永不到来的审批上。
完整的优先级顺序参见权限控制。
现象:
建议在回调之外缓存决策结果,而非反复提高超时时间。这里的每一毫秒都会叠加到每一轮请求上。
Java 的预算用
现象: Agent 已获得新知识,运行结束后却没有任何内容被保存。
生成在轮次结束之后由后台 Agent 执行。若进程在收到最终
Python 未使用
现象: 设置文件中已开启某项功能,但会话表现为未开启。
部分查询选项具有最终决定权:一旦传入,它会替换而非合并对应的设置块,未显式列出的开关全部按
现象: Agent 遵循了提示词中并不存在的约定。
运行 QoderCN CLI 的机器上的指令文件默认会被加载,且这些文件可以引入其他文件。可通过日志确认实际加载了什么:
若需在不同主机上获得可复现的运行结果,使用
以下问题只出现在 Java SDK。
现象: 启动或
现象: 启动以
现象: Windows 上启动以错误码
会话关闭后仍有残留时,SDK 通过诊断事件报告,不会抛出异常。注册方式见收集可用于上报的诊断信息。
完整的事件列表见
需要升级排查时,请在现场信息丢失前收集以下内容:
Java 的诊断监听器可以注册在客户端或单个会话(
会话始终无法启动
现象: query() 没有产出任何消息,或首个 await 长时间挂起后抛出异常。
| 原因 | 如何确认 | 解决办法 |
|---|---|---|
qoderclicn 可执行文件不在 PATH 中 | 异常为 QoderCliProcessError,且提示信息中包含可执行文件 | 设置 pathToQoderCLIExecutable,或导出 QODERCLI_PATH |
| 启动超出加载超时 | 每次都在固定时长后失败 | 提高 loadTimeoutMs;磁盘较慢时的冷启动可能超过默认值 |
| 未配置凭证 | 异常带有 code: 'auth_not_configured' | 传入 auth,参见认证 |
| 凭证环境变量未设置 | code: 'auth_access_token_env_var_not_configured' 或 ..._service_account_... | 导出认证辅助函数读取的那个变量 |
| 找不到 CLI(Java) | CliNotFoundException | qoderCliPath 指向的路径无效时修正路径;当前平台不在托管范围(例如 Windows arm64)时,用 qoderCliPath 或 QODERCN_PATH 指定已安装的 CLI |
| 托管 CLI 安装失败(Java) | RuntimeInstallException | 见托管 CLI 无法安装 |
| 临时目录不安全(Java) | UnsupportedSecureSecretTransportException | 见启动报 UNSUPPORTED_SECURE_SECRET_TRANSPORT |
| 凭证环境变量未设置(Java) | AuthenticationException,消息含 not set | 在启动 JVM 前导出该变量;putEnvironment() 传入的值不参与认证 |
stderr,其中通常直接指明了真实原因:
CliProcessException.getStderrTail() 返回有界且已脱敏的 stderr 尾部;启动和关闭过程的事件用诊断监听器收集,见收集可用于上报的诊断信息。
选项在进程启动前即被拒绝
部分选项会在前置阶段校验,因此拼写错误会立即失败,而非让某项功能被静默关闭。以下异常在 QoderCN CLI 启动之前同步抛出。
| 报错信息 | 原因 | 解决办法 |
|---|---|---|
securityScan contains unknown option: <key>security_scan contains unknown option: <key>. | 开关名拼写错误 | TypeScript 使用 l1StaticCheck / l2LightweightScan / l3DeepScan;Python 使用 l1_static_check / l2_lightweight_scan / l3_deep_scan |
securityScan.<key> must be a booleansecurity_scan.<key> must be a bool. | 传入了 'yes' 之类的字符串 | 传入 true 或 false |
security_scan must be a dict. | Python 侧传入了非映射类型 | 传入开关组成的 dict |
native mode requires at least one enabled scope; use memory: {} to disable SDK memorynative memory requires at least one enabled scope; use memory={} to disable | projectScope 与 userScope(Python 为 project_scope 与 user_scope)同时设为 false | 保留一个作用域,或用 memory: {}(Python 为 memory={})关闭记忆 |
[createSdkMcpServer] Server name must be a non-empty string. | name 缺失或为空 | 为服务指定名称 |
[createSdkMcpServer] Tool name must be a non-empty string in server "<server>". | 定义工具时未提供名称 | 为每个工具命名 |
[createSdkMcpServer] Tool "<tool>" must have a non-empty description string. | 缺少 description | 补充描述;模型依赖它判断何时调用该工具 |
QoderClient.Builder.build() 和 SessionOptions.Builder.build() 同样在启动前校验,失败时同步抛出 InvalidOptionsException,例如没有设置 auth,或同时设置了 resume 和 continueSession。完整规则见 SessionOptions.Builder。
SDK 与运行时版本不匹配
现象: ProtocolVersionMismatchError 或 UnsupportedCliCapabilityError(Java 为 ProtocolVersionMismatchException 或 UnsupportedCliCapabilityException)。
这表示 SDK 与 QoderCN CLI 来自不兼容的版本,通常出现在运行时由使用方单独管理、而非使用包内自带运行时的情况下。
UnsupportedCliCapabilityError.capability 会指明缺失的具体能力,据此可判断应升级运行时还是停用该选项。解决办法是升级 QoderCN CLI,或移除 pathToQoderCLIExecutable 覆盖,改用包内自带的运行时。
Java SDK 默认使用托管的锁定版本 CLI。出现不匹配时,检查是否通过 qoderCliPath 或 QODERCN_PATH 指定了其他版本;移除后 SDK 改用托管 CLI。UnsupportedCliCapabilityException.capabilityState() 返回 CLI 对该能力的声明状态。
Agent 始终不调用自定义工具
现象: 工具已注册、会话正常启动,但 Agent 绕过该工具完成了任务。
按以下顺序排查:
- 确认完整工具名。 服务名为
my_tools、工具名为greet时,模型看到的是mcp__my_tools__greet。白名单必须使用完整名称。 - 确认未被白名单排除。 若设置了
tools或allowedTools但未包含该工具,模型不会看到它。参见工具命名与白名单。 - 确认懒加载影响。 启用 MCP 懒加载后,工具不会全部常驻。对必须始终可用的工具做标记:
- 检查工具描述。 描述是模型判断该工具适用场景的唯一依据。「做某件事」这类描述会被忽略,应明确写出触发条件。
Agent 在本应有权限的操作上停住
现象: 工具调用被拒绝,或运行停滞在一个永不到来的审批上。
| 原因 | 解决办法 |
|---|---|
disallowedTools 覆盖了该工具 | disallowedTools 的优先级高于 allowedTools 和 permissionMode |
| 非交互任务中缺少审批处理 | 设置不需要交互提示的 permissionMode,或提供 canUseTool |
同时设置了 canUseTool 与 permissionPromptToolName | 两者互斥,只能择一 |
模型选择回调超时
现象: ModelPolicyTimeoutError。Java 不抛出异常,诊断监听器收到 inbound_control_request_failed 事件,detail 含 error=MODEL_RESOLUTION_TIMEOUT;本轮结果按 ResultMessage.outcome() 处理。
resolveModel 位于每次请求的关键路径上,默认预算为 500 毫秒。若回调中查询数据库或调用 HTTP 服务,将超出该预算。
SessionOptions.Builder.resolveModelTimeoutMs(long) 调整,默认同为 500 毫秒。超时后请求该模型的轮次失败,不会回退到其他模型。
记忆未被写入
现象: Agent 已获得新知识,运行结束后却没有任何内容被保存。
生成在轮次结束之后由后台 Agent 执行。若进程在收到最终 result 消息后立即退出,可能中断正在进行的写入。
daemon 选项时,单次 query() 在结束输入前自动 flush,QoderSDKClient 在 disconnect() 或退出上下文时自动 flush;自动 flush 失败只记录日志,需要确认成功时显式调用 flush_memory()。使用 daemon 选项且 CLI 声明了 daemon_async_session_teardown_v1 时,两者都不自动 flush,关闭完成不代表记忆已经写完;关闭后要立即读取记忆文件或启动下一个会话时,改用 QoderSDKClient,在关闭前调用 await client.flush_memory()。参见在运行时控制记忆。
Java 的一次性查询在 ResultMessage 之后还可能收到 Memory 消息,应把消息流读到结束再关闭。
若 flushMemory() / flush_memory() 已返回而文件仍无变化,请检查生成结果:no_change 和 skipped 属于正常结果,并非失败。参见查看记忆的执行结果。
在设置中开启的功能未生效
现象: 设置文件中已开启某项功能,但会话表现为未开启。
部分查询选项具有最终决定权:一旦传入,它会替换而非合并对应的设置块,未显式列出的开关全部按 false 处理。
securityScan 即属于此类。若 settings.json 开启了 l1StaticCheck,而查询传入 securityScan: { l3DeepScan: true },则本次会话的 l1StaticCheck 为关闭状态。需要保留的开关必须逐个重新声明。参见该选项覆盖设置,而非合并。
Agent 遵守了未曾设置的规则
现象: Agent 遵循了提示词中并不存在的约定。
运行 QoderCN CLI 的机器上的指令文件默认会被加载,且这些文件可以引入其他文件。可通过日志确认实际加载了什么:
settingSources: [] 不从磁盘加载任何文件。参见从文件系统加载指令。
Java 运行环境问题(Java)
以下问题只出现在 Java SDK。
托管 CLI 无法安装
现象: 启动或 installRuntime() 以 RuntimeInstallException(错误码 RUNTIME_INSTALL_FAILED)失败。SDK 不会改用其他版本的 CLI。
| 原因 | 解决办法 |
|---|---|
| 运行环境不能访问 Qoder 下载站点 | 在构建镜像或部署阶段预热缓存:java -cp qodercn-agent-sdk-VERSION.jar com.qoder.sdk.RuntimeInstaller(VERSION 为应用依赖的 SDK 版本);或随应用携带锁定的压缩包,用 ManagedRuntimeOptions.Builder.localArchive(Path) 指定 |
| 需要经过代理 | 下载按 JVM 进程环境中的 HTTPS_PROXY、ALL_PROXY 和 NO_PROXY 选择代理,在启动 JVM 前设置 |
| 只能访问企业镜像 | 用 ManagedRuntimeOptions.Builder.baseUrl(URI) 指向镜像,镜像按 <CLI 版本>/<文件名> 的布局提供相同的文件 |
禁止下载(DownloadPolicy.DISALLOW 或 --no-download)且缓存为空 | 先预热缓存,或提供本地压缩包 |
| 压缩包大小或 SHA-256 与锁定值不符 | 镜像或本地文件不是本 SDK 版本锁定的那一个。换成正确的文件,SDK 不提供跳过校验的选项 |
RuntimeInstaller 的参数和各项配置见预热与离线。
启动报 UNSUPPORTED_SECURE_SECRET_TRANSPORT
现象: 启动以 UnsupportedSecureSecretTransportException 失败,CLI 没有运行。
SDK 通过只有当前账号可读的临时文件把认证和 MCP 配置交给 CLI。java.io.tmpdir 或它的某一级上级目录允许其他账号在其中改名或替换条目时,SDK 拒绝启动,不会改用启动参数或环境变量传递凭据。只有当前账号可写的目录和带 sticky 位的公共目录(如 Linux 的 /tmp)满足要求。
解决办法:用 JVM 启动参数 -Djava.io.tmpdir=<dir> 指向只有当前账号可写的目录。
Windows 上自行指定的 .cmd CLI 拒绝启动
现象: Windows 上启动以错误码 CLI_START_FAILED 失败,消息含 refusing to launch a Windows batch-file CLI。
自行指定的 CLI 是 .cmd 或 .bat(例如 npm 安装的 qoderclicn.cmd),而 CLI 路径或启动参数含有 cmd.exe 会解释的字符,包括括号(如工具规则 Bash(git:*))。cmd.exe 可能改写这些参数,SDK 因此拒绝启动。
解决办法:不指定 CLI 路径,使用 SDK 托管的 CLI;或把 qoderCliPath 指向 .exe。自动查找时,同一目录中的 .exe 优先于 .cmd。
用诊断事件定位关闭与清理问题
会话关闭后仍有残留时,SDK 通过诊断事件报告,不会抛出异常。注册方式见收集可用于上报的诊断信息。
事件 type | 含义 | 处理方式 |
|---|---|---|
private_directory_cleanup_failed | 认证或 MCP 配置用的私有临时目录没有清理完成。detail 含 credential files may remain 时,凭据文件可能仍在磁盘上 | 按 detail 中的路径检查并删除残留目录 |
cli_process_alive_after_close | 关闭流程结束后 CLI 进程仍在运行,detail 列出已执行的终止步骤 | 在宿主侧确认并结束残留进程 |
process_tree_cleanup_degraded | 当前环境无法完整清理 CLI 进程树 | CLI 启动的子进程可能残留,在容器或进程组层面兜底清理 |
capability_downgraded | 已通过能力检查的控制请求在运行时被 CLI 判为不支持,capability 给出能力名 | 之后调用该功能会以 UnsupportedCliCapabilityException 失败。检查是否自行指定了其他版本的 CLI |
mirror_drain_timeout | 关闭时外部会话存储的写入没有在时限内完成 | 部分记录可能没有写入存储。检查存储后端的延迟,需要时调大 SessionMirrorOptions 的 closeDrainTimeoutMs |
DiagnosticEvent。
收集可用于上报的诊断信息
需要升级排查时,请在现场信息丢失前收集以下内容:
SessionOptions.Builder.diagnosticsListener)上;会话设置了监听器时只用会话级。托管 CLI 的 managed_runtime_* 事件只发给客户端级监听器。诊断是尽力交付的,不能当作无损审计日志。CLI 非正常退出时,同时记录 CliProcessException.getExitCode() 和 getStderrTail()。
同时记录 SDK 版本、system/init 消息中的 QoderCN CLI 版本、session_id,以及 Result 的 subtype 和可能存在的 error_code。除诊断流程明确需要,凭证、提示词和源码内容应做脱敏处理,参见日志与问题反馈。