Codex 环境初始化失败:6 个原因 + 最短修复路径

Codex 卡在 Setting up environment——多半是运行时版本不匹配、私有 registry 没 token,或安装太慢撑爆缓存容器。2026 年 6 月核实过的快速修法。

你给 Codex 云端派一个 task,它一直卡在 Setting up environment 过不去。setup 日志里要么是 npm error code E401,要么 python: command not found,要么干脆挂着、最后连 plan 都没出。Codex 根本没读到你的代码:容器连 setup 脚本都没跑完,agent 阶段压根没启动。

最快的修法(多数仓库适用):进 Codex settings → Environments,打开你的环境,点 Set package versions,把 Node / Python 钉到 lockfile 期望的版本。这能解决最常见的那类原因(运行时不匹配),还不用动 setup 脚本。如果日志里是 401 / E401,那是私有 registry 缺 token(跳到修法 3);如果结尾是 timeout 且没有具体包报错,那是安装超出预算(修法 5)。

Codex 云端用 openai/codex-universal 基础镜像构建容器,再跑你的 setup 脚本(带网络),跑完才把控制权交给 agent。截至 2026 年 6 月,几乎所有 setup 失败都落在六类:运行时版本不对、私有 registry 缺 token、安装太慢撞上缓存容器预算、缺原生编译依赖、缺系统包、setup 脚本中途静默失败。下面先教你判断属于哪一类,再给修法。

你属于哪一类?

把 setup 日志里第一个真正的报错对照下表。注意往下翻几行——根因常常被埋住,而不在最顶上。

日志特征大概率原因修法
EBADENGINEUnsupported enginerequires: node@…、Python SyntaxError: invalid syntax运行时版本不匹配修法 1
401403E401UnauthorizedNot Found,包名以 @your-org/ 开头私有 registry 缺 token修法 3
结尾是 timed out / timeout,没有具体包报错安装太慢、超出容器预算修法 5
gcc: command not foundPython.h: No such filepg_config: command not foundnode-gyp 报栈缺原生编译依赖修法 4
第一个报错不是真凶,build 在莫名其妙的地方挂脚本静默失败后继续往下跑修法 2
某个非公网域名报 getaddrinfo ENOTFOUNDECONNREFUSED503出站网络被禁修法 6

常见原因,按命中率从高到低

1. 项目运行时和基础镜像不匹配

截至 2026 年 6 月,codex-universal 镜像默认是 Node 22(同时装了 18 和 20)+ Python 3.12——不是有些旧教程还在写的 Node 20 / Python 3.11。如果你的 lockfile 是 Node 18 生成的,或者代码用了所钉版本不支持的 Python 特性,npm ci 会报 engine 错误,或者 import 直接崩。

如何判断:搜 EBADENGINEUnsupported enginerequires: node@<version>,或 Python 的 SyntaxError。setup 脚本开头加 node -v && python --version,版本不对一眼看出来。

2. 私有 npm / pip registry 缺 token

你的 package.json 从 GitHub Packages 或自建 Verdaccio 拉 @your-org/private-pkg。容器没有鉴权,npm ci 直接 401 Unauthorized(新版 npm 打印的是 npm error code E401)。

如何判断:日志里搜 401403UnauthorizedNot Found,配上你的 registry URL。失败的包名以 @your-org/ 开头就是它。

3. 安装超出缓存容器预算

Codex 会把容器状态缓存 最多 12 小时,让后续 task 更快;但冷启动的首次运行仍要一口气跑完 setup。大 monorepo 冷装 pnpm install,或者拉 500 MB 的 Playwright 浏览器包,可能跑太久导致 setup 失败。

如何判断:日志结尾是 timed out、没有具体包报错。本地同样安装,如果冷启动要好几分钟,那就是它。

4. 缺原生编译依赖

node-gypsharpnode-canvasbcryptlxmlpillowpsycopg2 需要 gccpython3-devlibpq-dev 之类。codex-universal 虽然全,但未必带你要编译的每个 -dev 头文件。

如何判断:搜 gcc: command not foundPython.h: No such filepg_config: command not found,或 node-gyp 的栈。原生编译失败日志很长,越过前 50 行才是真因。

5. setup 脚本失败后静默继续

你的 setup 脚本写的是 npm install && npm run build。install 半成功(有 warning 但退出码不是非零),脚本继续往下,build 在某个莫名其妙的地方挂掉——真因是上一步。

如何判断:日志里第一个 error 不是根因。脚本顶部加 set -euo pipefail 重跑,真正的错就浮出来并把脚本停在那。

6. 出站网络被禁或被限速

setup 阶段是有网络的,但公司 VPN 内自建的 registry 容器可能访问不到,大流量的 raw 下载也可能被限速。(注意:agent 阶段默认关网络,那影响的是运行时联网的代码,而不是你 setup 时的安装。)

如何判断:某个非公网域名报 getaddrinfo ENOTFOUNDconnect ECONNREFUSED、或 503 Service Unavailable。换个网络试同一 URL——那边能通就是容器出站被限。

最短修复路径

按收益从高到低。修法 1-3 覆盖”版本 / token / 原生依赖”三大件。

修法 1:在环境里钉版本,别只靠 dotfile

更现代、对缓存更友好的做法是直接在环境里钉。镜像会在容器启动时由 entrypoint 解析 CODEX_ENV_* 变量——比在脚本里重装运行时更快、更稳。

  • UICodex settings → Environments → 你的环境 → Set package versions → 选 Node / Python(及其他)。
  • 或用环境变量(同一处环境设置里):
CODEX_ENV_NODE_VERSION=20
CODEX_ENV_PYTHON_VERSION=3.11

截至 2026 年 6 月支持的取值:Node 182022;Python 3.103.113.123.133.14。(Go、Rust、Ruby、Java、Swift、PHP 也有对应变量,如 CODEX_ENV_GO_VERSION。).nvmrc / .python-version 这类 dotfile 仍可作兜底,但环境变量路线在缓存恢复时更不容易失效。

修法 2:让 setup 脚本 fail-fast 并打印上下文

放进你的 setup 脚本(在环境里配置,或仓库的 setup 文件):

#!/usr/bin/env bash
set -euo pipefail   # 首错即停 / 禁未定义变量 / pipe 失败也停

echo "=== Runtime versions ==="
node -v
python --version || echo "python not present"

echo "=== System deps ==="
which gcc make pkg-config || true

echo "=== Install ==="
# 用 ci 不用 install——确定性 + 更快
npm ci --no-audit --no-fund

echo "=== Build (只在有 build 脚本时跑) ==="
npm run build --if-present

echo "=== Setup done ==="

set -euo pipefail 是最关键的一行:它在首个错误处停下,而不是把失败级联到下游某个让你绕晕的地方。

一个常踩的坑:setup 脚本和 agent 跑在两个不同的 Bash 会话里,所以 setup 里的 export FOO=bar 不会带到 agent 阶段。如果 agent 运行时需要某个环境变量,把它写进 ~/.bashrc(或在环境设置里配成 environment variable),别在 setup 里裸 export

修法 3:从 Codex secret 生成 registry token

Secret 是加密存储的,并且按设计只在 setup 阶段可用——agent 阶段开始前就被移除。所以你必须在 setup 里写好 .npmrc,没法等到后面再鉴权。

  1. 生成只读 token(GitHub Packages 用 PAT + read:packages 权限)。
  2. 在 Codex 环境设置里加为 Secret,如 NPM_TOKEN
  3. 在 setup 脚本里从 secret 生成 ~/.npmrc:
cat > ~/.npmrc <<EOF
@your-org:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=${NPM_TOKEN}
always-auth=true
EOF

pip:

export PIP_INDEX_URL="https://${PYPI_USER}:${PYPI_TOKEN}@pypi.your-org.com/simple/"
pip install -r requirements.txt

绝不要 commit 真正的 .npmrc / pip.conf——只在 setup 时从 secret 生成。另外:改 secret 会让缓存容器失效,下一个 task 会用新值重建。

修法 4:原生编译依赖提前装

如果 package.json 里有 sharpcanvasbcrypt,或任何 node-gyp 系列,先装工具链(基础镜像是 Debian 系):

apt-get update -qq
apt-get install -y --no-install-recommends \
  build-essential \
  python3-dev \
  libpq-dev \
  libcairo2-dev libjpeg-dev libpango1.0-dev libgif-dev \
  libvips-dev   # sharp 需要

Python 里有 psycopg2lxmlpillow 的,加 libpq-devlibxml2-devlibxslt1-devlibjpeg-dev

更省事的是直接用预编译版本跳过编译:psycopg2psycopg2-binary,sharp 拉它自带的预编译 libvips 而不是从源码构建。

修法 5:让 install 更快,留在预算内

npm install 换成 npm ci(严格按 lockfile、跳过解析、更快更确定)。pnpm / yarn 同理:

# pnpm
pnpm install --frozen-lockfile --prefer-offline

# yarn (berry)
yarn install --immutable

Monorepo 只装 task 涉及的那块:

# pnpm workspace,只装 API 包
pnpm --filter @your-org/api install

因为 Codex 把容器缓存最多 12 小时,把慢且少变的步骤放进 setup 脚本(这样会被缓存),用可选的 maintenance 脚本只刷新缓存容器恢复时真正会变的那部分。这样重复 task 就快了。

修法 6:派 task 前先在本地验证 setup

别对着 Codex 那种只有 setup 的日志硬调。直接在同款基础镜像里复现:

docker pull ghcr.io/openai/codex-universal:latest
docker run --rm -it -v "$(pwd)":/repo -w /repo \
  ghcr.io/openai/codex-universal:latest bash
# 容器里:
bash ./setup.sh

那里跑通(配上同样的 secret),云端容器也能通。本地都跑不通,就在本地用全工具链修,比对着截断的日志猜省太多事。

怎么确认修好了

  1. 重新派一个 task,看 setup 日志跑到 === Setup done ===(或你最后那条 echo),再进入 agent 规划阶段。
  2. 确认 agent 阶段确实在改代码——setup 干净但 agent 卡住是另一类问题。
  3. 如果你改过运行时版本、secret,或 setup / maintenance 脚本,缓存已自动失效;如果行为看起来还是旧的,点环境页上的 Reset cache 再跑一次,干净重建。

预防建议

  • 在环境里钉运行时(Set package versions / CODEX_ENV_*),别赌基础镜像猜得对
  • 每个 setup 脚本顶部加 set -euo pipefail,让失败 loud 而不是 silent 地级联
  • registry token 存为 Secret,在 setup 里据此生成 .npmrc——secret 到 agent 阶段就没了,所以必须在 setup 阶段写
  • agent 阶段需要某个环境变量?写进 ~/.bashrc;setup 里裸 export 不会保留
  • 优先用预编译(psycopg2-binary、预编译 sharp),别让容器跑源码编译
  • npm ci / --frozen-lockfile——更快、确定、严格按 lockfile
  • 让冷启动 setup 尽量短,靠 12 小时缓存 + 小的 maintenance 脚本扛住重复 task

常见问题

setup 脚本和 secret 到底在哪配?Codex settings → Environments。打开你仓库对应的环境,setup 脚本、可选的 maintenance 脚本、环境变量和 secret 都在那。

为什么我在 setup 里 export 的变量在 agent 阶段没用? setup 和 agent 跑在两个不同的 Bash 会话里,setup 里 export 的变量不会带过去。改成写进 ~/.bashrc,或在环境设置里加成 environment variable。

我加了 secret,私有包还是 401,为什么? secret 只在 setup 阶段注入,所以 .npmrc(或 pip 鉴权)必须由 setup 脚本本身写好。如果你指望 agent 阶段才鉴权,会失败,因为 secret 在 agent 启动前就被移除了。另外确认 token 权限(GitHub Packages 要 read:packages),以及改 secret 后缓存容器已重建。

Codex 每个 task 都重跑整套 setup,能缓存吗? 容器状态会缓存最多 12 小时,但改 setup / maintenance 脚本、环境变量或 secret 都会让缓存失效、触发完整重建。保持它们稳定,把确实需要刷新的部分交给 maintenance 脚本。

云端镜像默认是哪个 Node 和 Python 版本? 截至 2026 年 6 月,codex-universal 默认 Node 22(18、20 也可选)+ Python 3.12,同时带 Go、Rust、Ruby、Java、Swift、PHP 工具链。任何一个都能用 CODEX_ENV_*Set package versions UI 钉死。

我的 setup 脚本能联网吗? 能——setup 阶段有网络用来装依赖。agent 阶段默认关网络,所以别指望运行时联网拉取,除非你给那个环境开了 internet access。

相关阅读

标签: #Codex #排查 #环境 #CI #依赖