乐于分享
好东西不私藏

Codex Bug:你用的AI编程助手正在悄悄杀死你的硬盘

Codex Bug:你用的AI编程助手正在悄悄杀死你的硬盘

CODEX · 日志Bug · SSD寿命

一个 TRACE 级日志配置,让 Codex 一年写入 640 TB。你的 1TB SSD 终身质保才 600 TBW。不到一年,硬盘报废。

一个开发者随手看了下自己 Mac 的磁盘写入量,然后整个人都不好了。

21 天,37 TB。

他用的是 OpenAI 的 Codex CLI——就是那个帮你写代码的 AI 助手。没有跑什么疯狂任务,就是日常用用。

换算一下:一年 640 TB 写入量。一块 1TB 消费级 SSD 的终身写入寿命大概 600 TBW。也就是说,不到一年,一块全新的固态硬盘就能被写到质保报废。

不是什么复杂的系统漏洞。是一个无聊到离谱的日志配置错误。

01

一个 Level::TRACE,毁掉你的硬盘

Codex 内部用了一个 SQLite 数据库来存反馈日志,文件就藏在你的电脑里:

~/.codex/logs_2.sqlite

加上它的两个伴生文件 -wal 和 -shm

问题出在哪?日志等级被设成了 TRACE——所有等级里最吵、最详细、最暴力的那档。

TRACE 是什么概念?就是你写个 console.log 都嫌不够细,它要把每一次 WebSocket 收包、每一次文件系统事件(包括你打开 /etc/passwd)全记下来。而且它完全绕过了 RUST_LOG=warn 环境变量——你设了也没用。

TRACE 日志占了 70.7% 的存储量,再加上两个 OpenTelemetry 类别(codex_otel.log_only 和 codex_otel.trace_safe),96% 的日志数据是普通用户永远不会去看的垃圾。

02

为什么文件没变大,硬盘却在疯狂写?

这里有个特别阴险的地方。你用 du -sh 看一眼 ~/.codex/,可能觉得不大啊,才一百多 MB?

被骗了。

SQLite 用了一种叫 WAL(Write-Ahead Logging)的机制。它的运作方式是:先写入 → 再删除 → 再写入 → 再删除……数据库文件大小几乎不变,但实际写入量是文件大小的几百倍。

GitHub 上有人做了一个 15 秒的采样:

保留行数:681,774(没变)。MAX(row id):从 5,003,347,015 跳到 5,003,383,226。15 秒,36,211 次插入。保留行数纹丝不动。

每秒钟超过 2,400 次"写入-删除"循环。AUTOINCREMENT 计数器跑到了 55 亿,但实际保留的行只有 50 多万——差距整整一万倍。

你以为 du 看到的就是真相。但在 WAL 模式下,文件大小是个谎言。真正的写入量藏在 WAL 文件的反复冲刷里。

03

不只是 Codex 的问题

这个 bug 从 2026 年 4 月就有人报告了。相关 issue 一抓一大把:

#17320:流式输出时 WAL 疯狂写入,5~16 MB/s#22444:WAL 文件无限增长,僵尸进程还持有文件句柄。#27911:另一个数据库 goals_1.sqlite 也在疯狂写,11 MB/s。#28997:WAL 文件涨到几十 GB。#29237:数据库超 200MB 后直接崩溃,macOS 报 zsh: trace trap

桌面版、CLI 版、VS Code 扩展版全部中招。

一个用户在 OpenAI 社区论坛的原话:"为什么这个 bug 被无视了这么久?它严重影响了我的工作流程。" 他甚至专门写了一个 Bash 脚本来自动清理 WAL 文件、杀掉 Codex 进程。

04

怎么确认你中招了?

三步检查,花不了一分钟。

第一步:看文件存不存在

ls -lh ~/.codex/logs_2.sqlite*

第二步:查日志等级分布

sqlite3 ~/.codex/logs_2.sqlite "SELECT level, COUNT(*) FROM logs GROUP BY level ORDER BY COUNT(*) DESC"

如果 TRACE 占比超过 70%,恭喜,中招了。

第三步:观察 WAL 增长

sqlite3 ~/.codex/logs_2.sqlite "SELECT MAX(id) FROM logs;"

等 15 秒再查一次。如果两次差值超过几千,你的硬盘正在被悄悄消耗。

05

最省事的办法:让 Codex 自己修自己

上面那些命令你要一条一条敲?太累了。

直接把下面这段话丢给 Codex,让它自己诊断、自己修。

打开一个新的 Codex 会话,粘贴这段 prompt:

帮我检查 ~/.codex/logs_2.sqlite 是否因 TRACE 日志持续高频写盘。步骤:1. 用 sqlite3 查 logs 表的日志等级分布,确认 TRACE 是否占比超过 50%2. 记录当前 MAX(id),等 15 秒再查一次,看差值是否超过 10003. 如果中招,先备份:cp ~/.codex/logs_2.sqlite ~/.codex/logs_2.sqlite.bak4. 用 SQLite trigger 拦截写入5. 执行 PRAGMA wal_checkpoint(TRUNCATE) 清理 WAL 文件6. 再次采样 MAX(id),等 15 秒对比,确认不再增长7. 检查 ~/.codex/logs_2.sqlite-wal 文件大小是否归零

对,你没看错。让 Codex 用 sqlite3 去查自己写出来的日志数据库,然后亲手把自己的写入通道堵上。

就像让一个话痨去做自我反省,然后给自己贴上胶带。

它会乖乖执行每一步:查日志分布、采样 MAX(id)、备份、建 trigger、checkpoint WAL、再验证。全程你只需要粘贴一句话,然后看着它输出结果。

这个方案的精髓在于:你不需要懂 SQLite,不需要记命令,不需要手动操作。你只需要告诉 Codex "去查一下你自己的日志是不是有问题"——而它恰好有权限、有工具、有能完成这一切。

如果你更喜欢手动操作,下面章节有完整的分步指南。

06

手动止血:三步搞定

OpenAI 在 6 月 22 日终于合并了修复 PR(#29432 和 #29457),但你可能还没更新到修复版本。在等正式更新之前,你可以自己动手止血。

第一步:备份

cp ~/.codex/logs_2.sqlite ~/.codex/logs_2.sqlite.bak

这个文件只存内部诊断日志,不存对话内容,丢了不影响你的工作。但备份总是没错的。

第二步:用 SQLite Trigger 拦截写入

社区用户 @synap5e 提出的方案——一行 SQL,直接在数据库层面拦截所有新日志插入:

sqlite3 ~/.codex/logs_2.sqlite "CREATE TRIGGER IF NOT EXISTS block_log_inserts BEFORE INSERT ON logs BEGIN SELECT RAISE(IGNORE); END;"

这个 trigger 的意思是:每次有新数据想插入 logs 表,直接静默忽略。Codex 不会报错,但什么也写不进去。写入瞬间归零。

第三步:Checkpoint 并清理 WAL

sqlite3 ~/.codex/logs_2.sqlite "PRAGMA wal_checkpoint(TRUNCATE);"

这一条命令会:把 WAL 文件里还没合并的数据写回主 .sqlite 文件,直接把 WAL 文件截断到 0 字节。执行完你会发现 -wal 文件从几百 MB 变成了 0 字节。

验证:确认修复生效

sqlite3 ~/.codex/logs_2.sqlite "SELECT MAX(id) FROM logs;"

等 15 秒再查一次。如果 MAX(id) 不变了,WAL 也不涨了——恭喜,你的硬盘安全了。

想恢复的时候:

sqlite3 ~/.codex/logs_2.sqlite "DROP TRIGGER IF EXISTS block_log_inserts;"

07

更简单粗暴的办法

如果你不想折腾 SQL,还有一个社区方案:把日志文件软链接到内存里

rm ~/.codex/logs_2.sqlite && ln -s /tmp/logs_2.sqlite ~/.codex/logs_2.sqlite

日志全部写进内存,重启就消失。反正那些日志你也不会看。

08

最让人不安的是什么?

不是 bug 本身。是这个 bug 从 2026 年 4 月就被报告了,拖了将近 3 个月才有人修。

中间有十几个相关 issue,无数社区帖子,甚至有人专门写了 Bash 脚本来自动清理 WAL 文件、杀掉 Codex 进程。OpenAI 的 codex doctor 命令会告诉你"数据库健康",但对几十 GB 的 WAL 文件视而不见。

数以万计的开发者不知道自己的 SSD 正在被一个日志配置慢慢磨损。你花几千块买的 SSD,本来能用五年。现在因为一个 Level::TRACE,可能只能撑一年。而你甚至不知道。

修复速查表

备份cp ~/.codex/logs_2.sqlite* ~/.codex/*.bak — 防手滑

拦截写入CREATE TRIGGER block_log_inserts ... — 从源头掐断

清理 WALPRAGMA wal_checkpoint(TRUNCATE) — 把几百 MB 的 WAL 清零

验证SELECT MAX(id) FROM logs 两次对比 — 确认不再增长

软链接(可选)ln -s /tmp/logs_2.sqlite ... — 直接写内存

如果你身边也有人在用 Codex,把这篇文章转给他。这不是危言耸听——37 TB 的写入量是实测数据,640 TB/年的推算基于 21 天的连续监测。

你的硬盘不会喊疼。但 NAND 闪存的写入寿命是有限的。

参考资料GitHub Issue #28224: Codex SQLite feedback logs can write ~640 TB/yearGitHub Issue #17320: Excessive SQLite WAL writes during streamingGitHub Issue #29237: CLI crashes with SIGTRAP when logs_2.sqlite growsGitHub Issue #28997: logs_2.sqlite-wal grows without boundNotebookCheck: OpenAI Codex has a bug that could kill your SSD in under a yearPR #29432 & #29457: Stop logging every Responses WebSocket event / Filter noisy targets

关注「硅基新智讯」,看懂 AI 不迷路

同步更新于知乎「硅基新智讯」