工作流
Codex exec 没有输出或异常退出?从输出流、退出状态到产物逐步排查
codex exec 无输出、脚本异常退出或 CI 显示成功却没结果?区分 stdout、stderr 与 JSONL,保存退出状态和最终消息,按错误阶段排查,并核验实际产物。
运行 codex exec 后终端空白,或者 CI 已经变绿却找不到结果,先不要重复执行原任务。看不到输出、进程退出、任务完成,是三个不同的判断。 如果原任务会改文件或调用外部服务,盲目重跑还可能重复操作。
本文处理 codex exec no output、非交互脚本异常退出与退出码判断。目标是保留现场,找出失败阶段,再核对真正需要的结果;自动化任务怎样划定范围,可另看 Codex 自动化任务指南。
先按现象找到检查起点
| 你看到的现象 | 先检查什么 | 通过这一层的证据 |
|---|---|---|
| 只有进度,没有最终回复 | 进程是否仍在运行,stdout 是否被重定向 | 找到本次最终消息或明确失败信息 |
| 终端空白,但结果文件有内容 | stdout、stderr 的捕获方式 | 能解释每条流去了哪里 |
使用 --json 后脚本解析失败 |
是否把 JSONL 当成单个 JSON | 能逐行读到完整事件对象 |
| 返回非零退出码 | 首个有效错误及发生阶段 | 找到参数、配置、认证或执行错误 |
| 返回 0,但文件没有生成 | 是否拿到了 Codex 的退出码,任务要求是否落实 | 目标路径、文件内容或其他产物实际匹配 |
| 一直不退出 | 最后事件、子命令或输入管道 | 能判断正在执行、等待输入还是连接重试 |
保留本次命令、时间和错误,先用下面的只读任务验证通道。日志可能含项目内容或凭据片段,不要直接上传整份日志。
1. 确认是在同一个环境运行
适用情况: 终端手动执行正常,脚本或 CI 失败;或者刚改过参数和配置。
在出问题的环境检查:
codex --version
codex exec --help
git rev-parse --show-toplevel
git status --short --untracked-files=all
macOS/Linux 另用 command -v codex、pwd;PowerShell 用 Get-Command codex、Get-Location。核对实际可执行文件、版本、目录,以及脚本是否使用不同的 CODEX_HOME、profile 或启动参数,不输出认证文件。
预期结果: 你知道失败发生在哪台主机、哪个 checkout 和哪个版本。官方要求 exec 默认在 Git 仓库中运行;如果第三条失败,先进入预期仓库,不用跳过仓库检查来掩盖目录错误。配置差异参见 config.toml 不生效排查。
帮助中没有某个参数,就先按这个版本的帮助调整。核验日的官方文档已说明 --full-auto 不再支持;旧脚本出现未知参数错误时,应更新调用方式,不把它当作模型没有响应。
2. 分别保存 stdout、stderr 和最终消息
官方 非交互模式文档说明:普通 exec 将进度写入 stderr,最终回复写入 stdout。-o 可以另存最终回复;使用 --json 后,stdout 则改为 JSONL 事件流。
macOS/Linux:用一次最小只读任务检查
在预期 Git 仓库中,用 Bash 或 zsh 执行下列代码。它将诊断文件放到新建临时目录,避免覆盖上一次结果。此任务会发起一次正常 Codex 请求,使用当前认证与额度。
codex_check_dir=$(mktemp -d "${TMPDIR:-/tmp}/codex-exec-check.XXXXXX")
if codex exec --sandbox read-only --color never \
-o "$codex_check_dir/final.txt" \
"这是输出通道检查。不要修改文件,不调用工具,只回复 CODEX_CHECK_OK。" \
</dev/null >"$codex_check_dir/stdout.txt" 2>"$codex_check_dir/stderr.txt"
then
codex_check_exit=0
else
codex_check_exit=$?
fi
printf 'exit=%s\nfiles=%s\n' "$codex_check_exit" "$codex_check_dir"
</dev/null 只用于这次无需管道输入的检查,防止把额外 stdin 当上下文;原任务需要 stdin 时不要照抄这一项。上面的 if 能在启用了 set -e 的脚本中保留非零退出状态。
预期结果: 请求正常完成时,stdout.txt 与 final.txt 中应能找到检查回复;stderr.txt 用于查看进度、警告或错误。可以用编辑器打开刚输出的目录逐个查看。不要把“stderr 有文字”直接判为失败,也不要先用 2>/dev/null 丢弃它。
如果失败: 即使文件为空也先保留,结合退出状态与 stderr 转到第 4 节。如果回复和文件都正常,原来的“无输出”更可能与捕获、重定向或原任务执行有关,继续对照原脚本。
Windows PowerShell:立即记录原生命令的退出码
在交互 PowerShell 终端里,也可将三份输出分开保存:
$codexCheckDir = Join-Path ([IO.Path]::GetTempPath()) ("codex-exec-check-" + [guid]::NewGuid())
New-Item -ItemType Directory -Path $codexCheckDir | Out-Null
codex exec --sandbox read-only --color never -o "$codexCheckDir/final.txt" "不要修改文件,不调用工具,只回复 CODEX_CHECK_OK。" > "$codexCheckDir/stdout.txt" 2> "$codexCheckDir/stderr.txt"
$codexCheckExit = $LASTEXITCODE
Write-Output "exit=$codexCheckExit"
Write-Output "files=$codexCheckDir"
$LASTEXITCODE 要在下一条原生命令之前保存;Bash/zsh 用的是 $?。已有 CI 脚本若配置了遇错中止策略,需要在自己的错误处理分支中保存原始状态,不把两种 shell 的语法混用。
3. 用 --json 判断执行到了哪一步
适用情况: 需要机器读取事件,或普通输出不足以判断进度。先完成上一节,再考虑这次额外请求,不必反复调用。
macOS/Linux 可在原来的临时目录保存第二次检查:
if codex exec --sandbox read-only --json \
-o "$codex_check_dir/json-final.txt" \
"不要修改文件,不调用工具,只回复 CODEX_CHECK_OK。" \
</dev/null >"$codex_check_dir/events.jsonl" 2>"$codex_check_dir/json-stderr.txt"
then
codex_json_exit=0
else
codex_json_exit=$?
fi
printf 'json_exit=%s\n' "$codex_json_exit"
每一行是一个 JSON 对象。安装了 jq 时,可运行 jq -r '.type' "$codex_check_dir/events.jsonl" 查看事件类型;没有它就用编辑器逐行看,不需要为了排障先安装工具。
| 事件或结果 | 能说明什么 | 还需要检查什么 |
|---|---|---|
thread.started、turn.started |
会话或本轮已经开始 | 不能据此认定任务完成 |
item.* |
某个消息或工具项在推进 | 查看具体项的状态与错误 |
turn.failed、error |
存在本轮失败或错误线索 | 阅读消息,判断是否有重试及最终终态 |
turn.completed |
本轮达到完成状态 | 任务要求、产物与验证是否满足 |
预期结果: 有完整事件和相应最终消息。--json 不等于“最终回复一定是 JSON”;如果下游要求固定 JSON 字段,要另用官方 --output-schema 并验证最终输出,不能直接把整个 JSONL 文件当成一个 JSON 文档。
文件停在中间事件时,先区分进程仍在运行、被 CI 超时终止、人工取消与连接失败。被截断的最后一行不能证明已完成,也不宜立即重跑有副作用的原任务。
4. 按实际错误修复,不把所有失败当作等待审批
| 错误阶段 | 具体操作 | 修复后如何验证 |
|---|---|---|
| 找不到命令、未知参数、TOML 解析失败 | 核对实际入口、帮助与报错行;只修正对应调用或配置 | 版本与帮助可读,原来的启动错误消失 |
| 401、凭据或登录错误 | 在同一执行环境核对认证,按 登录排障处理 | 最小只读任务拿到真实回复 |
| 必需 MCP 初始化失败 | 找出 required = true 的目标服务器,按 MCP 分阶段排查处理 |
初始化通过,再确认需要的工具可调用 |
| 写入被沙箱拒绝 | 核对任务确实需要改文件、目标目录与管理策略;仅对已授权的写任务选择 --sandbox workspace-write |
相关操作能完成,差异只在授权范围内 |
| 网络重试、断流或 429 | 保留具体错误、时间与重试信息;核对网络或服务返回的限制提示 | 同一环境的只读请求正常,再评估续做 |
| 子命令不结束、等待输入 | 看最后执行的工具;检查是否误启动开发服务器、watch 模式、交互程序,或上游管道未关闭 | 改为能自行结束的命令,保留其真实返回状态 |
exec 用于无需人工交互的执行,权限与审批策略需要事先明确。默认只读,配置与启动参数也可能影响行为;不要把等待审批写成所有非交互失败的原因,更不要默认关闭沙箱或跳过安全检查。
仍看不清执行阶段时,官方支持用 RUST_LOG 增加诊断级别。例如 macOS/Linux 对单次检查使用 RUST_LOG=info codex exec ...,其中 ... 表示沿用你已核对的完整参数,不能原样运行。exec 的诊断随运行输出,不应去寻找交互 TUI 专用日志。更多日志可能包含敏感内容,只保留与错误相关的脱敏片段。
5. 退出码为 0,为什么产物仍不存在?
先确认这是 Codex 进程的退出码。例如 codex exec ... | tee result.txt 在未设置管道错误传播时,shell 可能返回最后一个 tee 的状态;CI 的 continue-on-error、|| true 或外层包装脚本也可能掩盖失败。先用第 2 节无管道的捕获方式定位,再修正 CI 的状态传播,不靠页面绿色判断成功。
接着对照本次任务:
- 最终回复是不是只给了方案? 让它解释如何生成文件,不代表已经生成文件;
-o保存的也只是最终消息。 - 路径是否正确? 核对 runner 工作目录、checkout、worktree 和输出路径。主目录看不到修改时,参考 worktree 改动定位。
- 产物是否有效? 检查文件内容、JSON 字段、测试结果或明确提交,而不只看文件存在。旧文件不能证明本轮成功,使用新的输出目录或核对本轮差异。
完成标准: 原始进程状态已保留,本轮没有未处理的失败,最终消息与实际产物相符,任务要求的相关测试或检查通过。任何一项不明确,都继续查对应证据。
本地正常,CI 仍失败怎么办?
逐项比较执行文件版本、工作目录、认证来源、CODEX_HOME、profile、环境变量和网络。runner 没有你的本机登录态、依赖或文件,是需要验证的环境差异,不能靠复制整个本地配置目录修复。
GitHub Actions 的安装、认证与凭据隔离应使用 官方 Codex GitHub Action 指南。不要把 API Key 放在整个 job 的环境变量中让所有仓库脚本都可读取。本文的输出检查不代替 Action 自己的配置与安全流程。
仍失败时,整理:系统与 CLI 版本、脱敏后的完整命令、实际工作目录类型、是否使用管道、Codex 原始退出码、相关 stderr、最后几个完整事件,以及期望与实际产物。特定版本的 issue 可用于核对类似现象,不能替代你自己的日志,也不能据此断言长提示词、TTY 或某个参数是所有用户的根因。