`--strict-config` 为什么没拦住我的拼写错误:配置校验的触发时机

2026-08-09

配置写完不生效,是 Codex(OpenAI Codex)命令行用户最常撞的一堵墙。多数人的第一反应很自然:既然 Codex CLI 提供了 --strict-config,那就加上它,让它把我拼错的键名喊出来。

结果往往是——什么都没喊,命令照跑,配置照样不生效。

这篇就把这件事拆开:这个开关到底承诺了什么,我们在本机上量到的边界在哪,以及当它沉默的时候,你该按什么顺序往下查。

一、现象长什么样

典型场景是这样的。你想把推理强度调高,于是在 ~/.codex/config.toml 里加了一行,但手滑多打了一个字母:把 model_reasoning_effort 写成了 model_reasoning_effortt。你隐约觉得不对劲,于是命令行上带了 --strict-config,指望它替你把关。

Codex CLI 的 help 里对这个选项的原文说明是:config.toml 里出现本版本不认识的字段时直接报错退出。看起来正是你要的东西。

但命令跑起来了,没有任何未知字段的报错。你于是开始怀疑人生:是不是我配置文件路径写错了?是不是要重启?是不是这个版本坏了?

先别急着乱改。这里面其实混着好几种完全不同的失败,--strict-config 只覆盖其中一种,而且还挑时机。

二、怎么确认是这个问题:三条可执行的判定命令

排查配置问题的顺序,我建议固定成下面这三步,因为它们从「文件到底读进去没有」一路收敛到「这个键到底认不认」。

第一步:确认配置文件本身有没有被成功加载

codex doctor --summary

在 codex-cli 0.147.0(Windows 11)上,这条命令的输出按 Notes / Environment / Configuration / Updates / Connectivity / Background Server 分组,Configuration 组里有一行就叫 config。正常情况下它显示 loaded

这一行为什么关键?我们在 codex-cli 0.147.0(Windows 11)上故意灌了一段语法不合法的 TOML:

codex -c 'features=[unclosed' doctor --summary

命令没有崩溃退出,doctor 照常把所有检查跑完了,但 Notes 区里多出一行:

✗ config       config could not be loaded - Fix the reported config error, then rerun codex doctor.

这是本机实测里最有实用价值的一条:配置坏掉的时候 doctor 仍然能跑,并且会明确告诉你配置没加载成功。所以「改完配置没生效」的第一步永远是跑 doctor 看这一行,而不是去翻 --strict-config。如果这里是 ,说明你的 TOML 有语法问题(少个引号、括号没闭合、表头写错),根本还没轮到键名对不对的问题。

顺带记住状态符号: 是 ok, 是 idle, 是 notes 或 warn, 是 fail。结尾还有一行统计,形如 17 ok · 1 idle · 1 notes · 0 warn · 0 fail

第二步:确认这个开关的校验有没有被触发

我们直接构造了拼写错误来试:

codex -c model_reasoning_effortt=high --strict-config exec --help

在 codex-cli 0.147.0(Windows 11)上,这条命令正常打印了 help,没有报任何未知字段错误

这就是那条边界。可以推出的结论是:--strict-config 的校验发生在真正加载配置去跑会话的时候,而 --help 这类根本不进入会话的路径不会触发校验。所以任何把它描述成「任何情况下都会拦住拼写错误」的说法都是不成立的——至少在这个版本上不成立。

需要说明两点边界,免得你把结论用过头:其一,我们这次注入未知键用的是命令行的 -c,不是写在 config.toml 文件里;其二,我们没有发起过任何模型对话请求,所以「真正跑一次会话时它到底会不会报错」,本文不下结论,官方 help 的措辞是会报错退出,以官方为准。

第三步:对 features 类开关,直接看生效值

如果你改的是 features.* 下面的开关,有一条更直接的核对路径:

codex features list

它输出三列:特性名、所处阶段、当前生效值。这一列官方说明是「当前生效状态」;本机未实测命令行覆盖是否会反映在这里,以官方说明为准。

在 codex-cli 0.147.0(Windows 11)上,unified_exec 这一项的生效值是 false。而官方《Configuration Reference》里 features.unified_exec 标的默认值是 true,但特意注明了 Windows 除外。两边对上了。这就是一次很典型的交叉印证:你以为自己配置没生效,其实是平台差异,跟拼写一点关系都没有。

三、官方与实测给出的处置

按上面三步查完,处置分三种走向。

如果 doctor 报 ✗ config:先修 TOML 语法。命令行的 -c 也算在内——官方对 -c, --config <key=value> 的说明是:点号路径表示嵌套(foo.bar.baz),value 按 TOML 解析,解析失败则按字面字符串处理。最后半句要划重点:-c 的值解析失败不会报错,会被当成字符串塞进去。所以 -c 传复杂结构时务必用单引号裹住整体,官方给的三个例子是 -c model="o3"-c 'sandbox_permissions=["disk-full-read-access"]'-c shell_environment_policy.inherit=all

如果 doctor 是 config loaded,但行为仍不对:把 --strict-config 挪到一个真正会加载配置去跑会话的调用上,而不是挂在 --help 后面。别指望在 --help--version 这类路径上验配置。

如果你要做二分法定位codex exec 有一个专有选项 --ignore-user-config,作用是不加载 $CODEX_HOME/config.toml。用它跑一次,如果异常消失,说明问题确实出在用户配置里;如果异常还在,那用户配置是清白的,得往别处查。注意它的一个细节:auth 仍然使用 CODEX_HOME,也就是说它只跳过配置,不影响登录状态。

另外别忘了配置是叠加的。-p, --profile <CONFIG_PROFILE_V2> 会把 $CODEX_HOME/<name>.config.toml 叠加到基础用户配置之上。如果你平时习惯带 profile,那你改的那份文件可能压根不是最终生效的那一层。

四、处置后怎么验证

验证不要靠「感觉好像生效了」,要靠可复现的输出:

  1. 重新跑 codex doctor --summary,确认 Configuration 组的 config 回到正常状态,并且结尾统计行的 fail 计数是 0。
  2. 如果改的是 features 开关,跑 codex features list,直接看那一行的生效值是不是你期望的。
  3. 跑一次 codex --version 把版本号记下来。这一步不是形式主义,理由见下一节。

顺便说一句,codex doctor --json 的官方说明是「Emit a redacted machine-readable report」——它是脱敏的。所以如果你查不动了要开 issue 求助,贴 --json 的输出比贴截图安全,也比你自己手动打码可靠。

五、什么情况说明不是这个原因

这一节是我最想让你读完的,因为配置排查最容易的死法就是认准一条路走到黑。以下几类问题,--strict-config 天然管不着,你再怎么加也没用。

第一类:键名对,但值非法。 这类错误的兜底不在配置层而在参数解析层。在 codex-cli 0.147.0(Windows 11)上执行 codex -s bogus-mode,得到的是:

error: invalid value 'bogus-mode' for '--sandbox <SANDBOX_MODE>'
  [possible values: read-only, workspace-write, danger-full-access]

For more information, try '--help'.

看到 possible values 这种格式,说明是命令行参数层拦下来的,跟 config.toml 无关,也跟 --strict-config 无关。这类报错反而是最好修的,人家已经把合法取值列给你了。

第二类:键名对、值也合法,但你把语义理解反了。 这类 --strict-config 一定沉默,因为从它的角度看你写得完全正确。举三个官方文档里真实存在、且特别容易理解反的例子:

  • shell_environment_policy.ignore_default_excludes 默认 true,含义是保留(而不是排除)名字里含 KEY、SECRET、TOKEN 的环境变量。光读键名很容易理解反。
  • web_search 默认值是 cached,取值有 disabled / cached / indexed / live。默认既不是关闭也不是实时,你以为「没配就是关的」,其实不是。
  • MCP 服务器的 disabled_tools 是在 enabled_tools 之后套用的。两个都配的时候以 deny 为准,不是以你写在前面的那个为准。

第三类:这个开关已经不再由你控制。 codex features list 里的阶段列一共观测到五种取值:stableunder developmentexperimentaldeprecatedremoved。在 codex-cli 0.147.0(Windows 11)上有一个反直觉的现象:removed 阶段的特性仍然会出现在列表里,而且部分 removed 项的生效值是 true(例如 steer)。

这说明 removed 指的是「这个开关本身不再需要你控制、行为已经固化」,而不是「功能没了」。所以如果你在配置里给一个 removed 的特性赋值却毫无反应,那不是拼写问题,是这一层控制已经不存在了。同理,标着 under developmentexperimental 的开关(本机观测到 network_proxyprevent_idle_sleep 属 experimental,code_modetoken_budgetstandalone_web_search 属 under development),本来就不该当稳定功能来依赖,它们的行为随版本变动是正常的。

第四类:版本变了。 这条很容易被忽略。同一台机器上,我们采集时开头跑 codex --version 得到 codex-cli 0.131.0,十几分钟后再跑同一条命令得到 codex-cli 0.147.0,而 which -a codex 全程只有一个可执行文件。Codex 具备自更新能力(config 里有 check_for_update_on_startup,默认 true)。

这意味着「本版本不认识的字段」这句话里的「本版本」是个移动靶。昨天报错今天不报、或者反过来,都可能只是版本变了。所以排查任何配置或版本相关的问题,都要以当次 codex --version 的实时输出为准,别用记忆里的版本号,也别用同事截图里的版本号。

六、一段可以照抄的最小验证配置

如果你只是想确认自己的改动路径是通的,可以先写一段最小的、键名都来自官方文档的配置,再往上加东西:

model_reasoning_effort = "high"

[shell_environment_policy]
inherit = "core"

以上为按官方文档键位组合的示例,未逐项实测,以官方文档为准。写完之后,先 codex doctor --summaryconfig 那一行,再把复杂的部分一块一块加回去。每加一块跑一次 doctor,比一次性写完然后对着一个不生效的系统干瞪眼要快得多。

说到底,--strict-config 是个有用但很窄的工具:它盯的是「本版本不认识的字段」,而且要在真正加载配置去跑会话的路径上才会发力。真正每次都能给你确定答案的,是 codex doctor --summary 的那一行 config,和 codex features list 里那一列生效值。

相关阅读


本文依据 Codex 官方文档(learn.chatgpt.com/docs/ 的《Configuration Reference》页面)整理,核对日 2026-08-09;文中标注「本机实测」的部分基于 codex-cli 0.147.0 / Windows 11 环境下的只读命令输出。产品功能、模型与价格以官方最新说明为准。

想系统学会用 AI?报名体系课或加入会员,照着学、照着用。