Codex 大 bug:为什么说它可能“烧穿硬盘”,以及怎么处理

最近看到一篇文章在说 Codex 有一个“史诗级大 bug”,标题很吓人:随时准备烧穿你的硬盘。

我一开始也觉得这个说法有点夸张,但排查之后发现,它背后的核心问题确实存在:某些版本或运行状态下,Codex 会把大量内部诊断日志写进本地 SQLite 数据库,尤其是 TRACE 级别日志。文件本身看起来可能只有几百 MB,但底层可能在持续写入,长期运行会增加 SSD 的写入量。

这篇文章整理一下整个事情的原因、排查方式和处理方法。

一、这个 bug 到底是什么

Codex 会在本机目录下维护一些状态文件和日志文件,其中一个比较关键的文件是:

~/.codex/logs_2.sqlite

这是一个 SQLite 数据库,主要用来存 Codex 自己的内部诊断日志。

问题出在:里面可能会写入大量非常细的 TRACE 日志,比如:

  • 网络连接状态
  • websocket 收发状态
  • SSE/HTTP 客户端内部事件
  • MCP 连接管理
  • Codex 内部调试信息

这些日志对普通用户基本没用,但如果持续高频写入,就会带来额外磁盘写入。

更麻烦的是,SQLite 通常还会配合 WAL 文件写入:

~/.codex/logs_2.sqlite-wal

所以你看到 logs_2.sqlite 文件大小没怎么变,不代表硬盘没被写。因为它可能一直在插入、删除、刷 WAL,实际 SSD 写入量比文件大小变化更高。

二、为什么这会影响硬盘

SSD 有一个指标叫 TBW,大概可以理解为“这块硬盘一生可以承受多少写入量”。

普通使用下,这个指标很难被用完。但如果某个程序长期持续写日志,尤其是每秒几 MB 这种级别,就可能明显消耗 SSD 寿命。

这件事的危险点在于:

文件大小不一定持续变大,但底层写入可能一直发生。

所以只看 Finder 里的文件大小,可能会低估问题。

三、可能出现什么现象

如果中招比较严重,可能会出现:

  • Codex 越用越卡
  • 切换会话变慢
  • 电脑磁盘 IO 增加
  • 风扇、发热、耗电增加
  • ~/.codex/logs_2.sqlitelogs_2.sqlite-wal 持续变化
  • TRACE 日志占比很高

如果只是轻度情况,可能暂时感觉不到明显卡顿,但日志仍然在持续写。

四、怎么排查自己有没有中招

可以先看文件大小:

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

再看日志级别分布:

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

如果看到类似:

TRACE|很多很多
INFO|一些
DEBUG|一些
WARN|少量
ERROR|少量

并且 TRACE 占大头,就说明确实有这个问题的特征。

还可以看估算写入量:

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

如果 TRACESUM(estimated_bytes) 明显高于其他级别,就更能说明问题。

再观察一分钟,看它是否还在增长:

sqlite3 ~/.codex/logs_2.sqlite "SELECT COUNT(*), SUM(estimated_bytes) FROM logs;"
sleep 60
sqlite3 ~/.codex/logs_2.sqlite "SELECT COUNT(*), SUM(estimated_bytes) FROM logs;"

如果一分钟后行数和 estimated_bytes 还在明显增加,就说明日志仍在写入。

五、解决思路有哪些

常见处理方式有三种。

方案一:加 SQLite trigger 阻止日志继续插入

这是我最推荐普通用户使用的方式。

思路是:给 logs 表加一个触发器。以后 Codex 想往日志表里写内容时,SQLite 直接忽略这次插入。

命令如下:

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

这个方案的效果是:

  • 不让 Codex 继续写这张日志表
  • 减少无意义的磁盘写入
  • 不影响项目代码
  • 不影响 Git
  • 不影响日常让 Codex 写代码、读文件、跑命令

主要代价是:以后本机少了 Codex 内部诊断日志。如果 Codex 自己出问题,官方或开发者可能少一份本地日志用来分析。

对普通用户来说,这个影响通常很小。

方案二:把日志文件软链到内存盘或临时目录

这个方式的思路是:日志照样写,但不写到主 SSD 上,而是写到内存盘或临时目录。

好处是不用改数据库逻辑。

缺点是操作更复杂,重启后可能要重新处理,对不熟悉命令行的人不太友好。

所以我不太推荐普通用户优先选这个。

方案三:删除或清空日志文件

这个只能释放空间,不能解决继续写的问题。

也就是说,你删掉之后,Codex 可能还会继续写回来。

所以这个方案只能作为辅助,不是根本解决。

六、推荐处理流程

更稳妥的做法是:先备份,再加 trigger。

备份命令:

sqlite3 ~/.codex/logs_2.sqlite ".backup '$HOME/.codex/logs_2.sqlite.bak-before-block-log-inserts'"

创建 trigger:

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

确认 trigger 是否存在:

sqlite3 ~/.codex/logs_2.sqlite "SELECT type, name, tbl_name, sql FROM sqlite_master WHERE type='trigger';"

如果看到:

trigger|block_log_inserts|logs|CREATE TRIGGER ...

说明已经生效。

再观察一分钟:

sqlite3 ~/.codex/logs_2.sqlite "SELECT COUNT(*), SUM(estimated_bytes) FROM logs;"
sleep 60
sqlite3 ~/.codex/logs_2.sqlite "SELECT COUNT(*), SUM(estimated_bytes) FROM logs;"

如果两次结果一样,说明日志插入已经被挡住了。

七、为什么建议先备份

严格说,logs_2.sqlite 主要是 Codex 的内部诊断日志,不是项目代码,也不是 Git 仓库内容。

但它毕竟是 Codex 自己维护的数据库。改数据库前备份,是一个比较稳妥的习惯。

备份的好处是:

  • 如果以后 Codex 官方修复了这个问题,可以恢复原状
  • 如果发现 Codex 某个功能异常,可以撤回修改
  • 如果误操作了,也有回退点

备份会多占一点空间。比如原文件 268 MB,备份也大概 268 MB。一般来说这点空间不算什么,确认几天没问题后也可以删除备份。

八、如何恢复原状

如果只是想移除 trigger,可以执行:

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

如果想恢复备份文件,可以先退出 Codex,然后执行类似:

cp ~/.codex/logs_2.sqlite.bak-before-block-log-inserts ~/.codex/logs_2.sqlite

恢复前最好先确认 Codex 没在运行,避免数据库正在被使用。

九、这件事要不要恐慌

不需要恐慌,但值得处理。

如果你的日志每分钟只是小幅增加,那还不是最严重的情况。但从长期来看,让一个没有实际价值的内部 TRACE 日志持续写 SSD,没有必要。

尤其是新电脑、新 SSD,更适合提前止损。

我的判断是:

这不是会立刻毁掉电脑的 bug。
但它是一个不该长期放着不管的无意义写盘问题。

普通用户最实用的处理方式就是:

备份 logs_2.sqlite
加 trigger 阻止 logs 表继续插入
观察确认不再增长
正常使用 Codex

这样成本很低,也能避免日志继续磨盘。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐