Codex 会话丢失恢复实战:切换 Provider 后历史列表为空的排查与修复
适用场景:使用 Codex(VS Code 扩展 / 桌面应用)时,在「官方 ChatGPT 账号」与「第三方 Provider」之间切换登录,切换后发现会话历史列表完全为空,但本地数据其实还在。
本文基于一次真实故障排查记录编写,命令、路径、输出均来自本次实际操作。环境不同时请把路径和 Provider 名替换成你自己的。
一、问题现象
在 VS Code 的 Codex 面板里,会话历史列表完全为空,只能新建对话,看不到任何旧会话。
发生背景:
- 原来用官方 ChatGPT 账号登录 Codex,积累了从 2026-02-27 到 2026-08-01 的 215 个本地会话。
- 某天切换到第三方 Provider,并用了一个第三方小工具「Codex Provider History Fixer 0.2.1」迁移历史。
- 之后又切回官方 ChatGPT 账号,再次用这个工具迁移,结果历史列表就空了。
二、环境信息
本次实测环境:
| 项 | 值 |
|---|---|
| 操作系统 | Windows 10 Pro(19045),中文环境 |
| VS Code | 1.132.0 |
| Codex 扩展 | openai.chatgpt 26.803.41515(win32-x64) |
| 扩展内置 CLI | codex-cli 0.147.0-alpha.6.5 |
| Codex 数据目录(CODEX_HOME) | C:\Users\hwy\.codex |
| 会话索引库 | C:\Users\hwy\.codex\state_5.sqlite |
提示:Codex 的 CLI/扩展/桌面应用共享同一个数据目录。Windows 下默认是
%USERPROFILE%\.codex。
三、关键数据文件
先弄清 Codex 的数据都放在哪,排查才有方向:
路径(相对CODEX_HOME) |
作用 |
|---|---|
state_5.sqlite |
会话线程索引库,threads 表记录每个会话的标题、预览、路径、Provider 等 |
sessions\YYYY\MM\DD\rollout-*.jsonl |
会话正文,每行一条 JSON(JSONL 格式),第一条通常是session_meta |
session_index.jsonl |
CLIcodex resume 用的会话索引 |
config.toml |
配置(模型、Provider、MCP 等) |
auth.json |
登录凭证(auth_mode 为chatgpt 表示官方账号登录) |
backups\provider-migration-* |
迁移工具每次改数据前做的全量备份 |
archived_sessions\ |
归档会话 |
四、初步判断:数据真的丢了吗?
故障排查第一步是确认数据是否还在,而不是急着恢复。
用任意 sqlite 工具打开 state_5.sqlite(本文用 sqlite3.exe):
# 查看会话线程总数、Provider 分布
sqlite3 C:\Users\hwy\.codex\state_5.sqlite "SELECT model_provider, COUNT(*) FROM threads GROUP BY model_provider;"
sqlite3 C:\Users\hwy\.codex\state_5.sqlite "SELECT COUNT(*) FROM threads WHERE preview <> '' AND archived = 0;"
# 校验数据库完整性
sqlite3 C:\Users\hwy\.codex\state_5.sqlite "PRAGMA integrity_check;"
本次实测输出:
chatgpt|215 # 215 个线程,Provider 全部是 chatgpt
210 # 可见线程 210 个(有预览、未归档)
ok # 数据库完整性正常
再确认会话正文文件是否完好:
(Get-ChildItem C:\Users\hwy\.codex\sessions -Recurse -Filter *.jsonl -File).Count
实测为 212 个活跃文件,全部可被 JSON 解析。
结论:数据一条没丢。 问题出在「会话索引里的 Provider 标签」与「应用当前默认 Provider」不一致,导致界面过滤后一个会话都匹配不上。
五、排查路径:Provider 标签是怎么错的
5.1 会话列表的过滤机制
Codex 的 app-server 在列出会话时,会按 threads 表的 model_provider 列过滤。应用当前用什么 Provider,就只显示 model_provider 等于该值的会话。
当前应用用的 Provider 由配置决定。用扩展自带 CLI 跑一次诊断(这条命令是排查的关键):
& "C:\Users\hwy\.vscode\extensions\openai.chatgpt-26.803.41515-win32-x64\bin\windows-x86_64\codex.exe" doctor
路径里的
26.803.41515是扩展版本号,以你环境为准;也可以直接用全局安装的codex doctor。
本次实测关键输出:
default model provider openai # 应用当前默认 Provider = openai
rollout DB rows 215
rollout DB model providers chatgpt=215 # 但会话索引里的 Provider 全是 chatgpt
rollout files and state DB thread inventory agree # 文件和索引是自洽的
rollout DB scan errors 0
对比很明显:
- 应用默认 Provider:openai
- 会话索引里的 Provider:chatgpt
两者不一致 → model_provider IN ('openai') 匹配 0 条 → 历史为空。
5.2 迁移工具到底做了什么
第三方工具「Codex Provider History Fixer」的源码逻辑(本文通过解析其安装目录下的 dist-electron\core\historyStore.js、sessionFiles.js 确认):
- 改数据前,先把
state_5.sqlite、sessions\全量备份到backups\provider-migration-<时间戳>\; - 执行
UPDATE threads SET model_provider = '<目标>' WHERE model_provider IN ('<源>'); - 逐个改写每个
sessions\**\*.jsonl里session_meta.payload.model_provider。
也就是说,它只改数据标签,不会改 config.toml。这就埋下了雷:
- 你告诉它「迁移到 chatgpt」,它就把所有会话标签改成
chatgpt; - 但应用从配置读取的默认 Provider 仍是
openai; - 于是标签和应用预期错位,界面列表为空。
5.3 备份对照,还原原始值
用迁移工具留下的备份可以还原出会话标签的“历史轨迹”:
# 首次迁移前(切第三方之前):大多数会话是 openai
sqlite3 C:\Users\hwy\.codex\backups\provider-migration-20260806-164941\state_5.sqlite "SELECT model_provider, COUNT(*) FROM threads GROUP BY model_provider;"
# 第二次迁移前(切回官方之前):全部变成 1
sqlite3 C:\Users\hwy\.codex\backups\provider-migration-20260807-190233\state_5.sqlite "SELECT model_provider, COUNT(*) FROM threads GROUP BY model_provider;"
实测输出:
# 备份1(0806)
openai|213
toskaxy|1
1|1
# 备份2(0807)
1|215
结论明确:原始可用的标签是 openai,与 doctor 报告的默认 Provider 完全吻合。
六、根因总结
Codex 会话索引(
state_5.sqlite.threads.model_provider)和会话文件(session_meta)里的 Provider 标签,被第三方迁移工具改成了chatgpt;而 Codex 应用在官方 ChatGPT 账号 + 默认配置下的 Provider 是openai。app-server 列出会话时按model_provider过滤,标签与预期不一致,导致 215 个会话全部被过滤掉,界面显示为空。会话数据本身没有丢失,只是“身份证上的 Provider 标签”与“应用认为当前用的 Provider”对不上。
七、最终修复
修复思路:把 Provider 标签恢复成应用默认值 openai。整个流程分四步:备份 → 停进程 → 改库 → 改会话文件。
风险提示:以下操作会直接修改 Codex 的数据文件。务必先做第 7.1 步备份,且提前关闭 Codex(扩展/桌面应用)和迁移工具进程,避免文件被占用或再次被改写。
7.1 第一步:完整备份(强烈建议,不跳过)
$ts = Get-Date -Format "yyyyMMdd-HHmmss"
$snap = "C:\Users\hwy\.codex\backups\manual-snapshot-$ts"
New-Item -ItemType Directory -Path $snap -Force | Out-Null
New-Item -ItemType Directory -Path "$snap\sessions" -Force | Out-Null
Copy-Item "C:\Users\hwy\.codex\state_5.sqlite" "$snap\state_5.sqlite" -Force
foreach ($s in @('state_5.sqlite-wal','state_5.sqlite-shm')) {
if (Test-Path "C:\Users\hwy\.codex\$s") { Copy-Item "C:\Users\hwy\.codex\$s" "$snap\$s" -Force }
}
foreach ($f in @('session_index.jsonl','config.toml','auth.json')) {
if (Test-Path "C:\Users\hwy\.codex\$f") { Copy-Item "C:\Users\hwy\.codex\$f" "$snap\$f" -Force }
}
Copy-Item "C:\Users\hwy\.codex\sessions" "$snap\sessions" -Recurse -Force
Write-Output "备份完成:$snap"
校验备份是否完整:
$sqlite = "C:\d\Anaconda3\envs\yolo\Library\bin\sqlite3.exe" # 换成你的 sqlite3 路径
& $sqlite "$snap\state_5.sqlite" "PRAGMA integrity_check;" # 期望输出 ok
(Get-ChildItem "$snap\sessions" -Recurse -Filter *.jsonl -File).Count # 与源 sessions 数量一致
7.2 第二步:关闭 Codex 与迁移工具进程
改库前先停掉可能占用数据库的进程,避免锁库或写入冲突:
# 结束 VS Code 扩展的 codex app-server 子进程(VS Code 本体不用关)
Get-Process -Name "codex" | Where-Object { $_.Path -like "*openai.chatgpt*" } | ForEach-Object { Stop-Process -Id $_.Id -Force }
# 结束迁移工具(如果还开着)
Get-Process | Where-Object { $_.ProcessName -like "*History*Fixer*" } | ForEach-Object { Stop-Process -Id $_.Id -Force }
注意:这只结束 Codex 扩展的子进程,不会关闭 VS Code,你正在编辑的文件不受影响。扩展会在下次打开面板时自动重新拉起 app-server。
7.3 第三步:修改会话索引库(state_5.sqlite)
把全部线程的 Provider 改回应用默认值 openai:
sqlite3 C:\Users\hwy\.codex\state_5.sqlite "UPDATE threads SET model_provider='openai' WHERE model_provider <> 'openai';"
sqlite3 C:\Users\hwy\.codex\state_5.sqlite "PRAGMA wal_checkpoint(TRUNCATE);"
校验(期望 openai|215 且 integrity_check 为 ok):
sqlite3 C:\Users\hwy\.codex\state_5.sqlite "SELECT model_provider, COUNT(*) FROM threads GROUP BY model_provider;"
sqlite3 C:\Users\hwy\.codex\state_5.sqlite "PRAGMA integrity_check;"
7.4 第四步:修改会话文件里的 session_meta
每个 sessions\**\*.jsonl 的第一条 JSON(session_meta)里也有 Provider 标签,需要一并改,否则会出现「索引是 openai、文件还是 chatgpt」的不一致。
关键:只改
session_meta行,不要把会话正文里出现的其他model_provider一起改掉。用精确字符串"model_provider":"chatgpt"替换,避免误伤。
$files = Get-ChildItem C:\Users\hwy\.codex\sessions -Recurse -Filter *.jsonl -File
$enc = New-Object System.Text.UTF8Encoding($false) # 必须 UTF-8 无 BOM,避免中文乱码
$changed = 0
foreach ($f in $files) {
$text = [System.IO.File]::ReadAllText($f.FullName)
$eol = if ($text.Contains("`r`n")) { "`r`n" } else { "`n" }
$hasTrailing = $text.EndsWith("`n")
$lines = $text -split '\r?\n'
if ($hasTrailing -and $lines.Count -gt 0 -and $lines[$lines.Count-1] -eq "") { $lines = $lines[0..($lines.Count-2)] }
$modified = $false
for ($i = 0; $i -lt $lines.Count; $i++) {
if ($lines[$i] -match '"type"\s*:\s*"session_meta"' -and $lines[$i].Contains('"model_provider":"chatgpt"')) {
$lines[$i] = $lines[$i].Replace('"model_provider":"chatgpt"','"model_provider":"openai"')
$modified = $true
}
}
if ($modified) {
[System.IO.File]::WriteAllText($f.FullName, ($lines -join $eol) + $eol, $enc)
$changed++
}
}
Write-Output "已修改 $changed 个会话文件"
如果迁移工具曾把会话标签改成过别的值(例如本文遇到的 "1"),把脚本里的 '"model_provider":"1"' 也替换成 '"model_provider":"openai"' 再跑一次即可。
改完验证所有文件仍是合法 JSON:
$bad = 0
Get-ChildItem C:\Users\hwy\.codex\sessions -Recurse -Filter *.jsonl -File | ForEach-Object {
foreach ($ln in [System.IO.File]::ReadAllLines($_.FullName)) {
if ($ln.Trim()) { try { $ln | ConvertFrom-Json | Out-Null } catch { $bad++; Write-Output "损坏: $($_.Name)" } }
}
}
Write-Output "损坏文件数:$bad" # 期望 0
八、验证结果
- 再次运行
codex doctor,关键输出应与下面一致:
default model provider openai
rollout DB model providers openai=215
rollout files and state DB thread inventory agree
rollout DB scan errors 0
state DB ... state_5.sqlite (file) · integrity ok
- 打开 VS Code 的 Codex 面板(触发 app-server 重新拉起),历史列表恢复显示全部旧会话,可正常点开继续对话。
本次实测两者都通过。
九、避坑总结
- 先确认数据还在,再动手恢复。 检查
state_5.sqlite的线程数和完整性,别急着删重建。 - Provider 标签必须与应用默认 Provider 一致。 官方 ChatGPT 账号 + 默认配置下,
codex doctor报告的default model provider就是会话索引里该填的值(本机为openai)。 - 迁移工具只改数据,不改配置。 所以“迁移到 chatgpt”之后,应用仍然按
openai过滤,必然空列表。这是此类工具的固有坑。 - 改数据前必备份。 迁移工具自己都会先备份(
backups\provider-migration-*),你手动改更应该备份。 - 改库前停进程。 先结束 Codex app-server 和迁移工具,避免锁库。
- 改 JSONL 用 UTF-8 无 BOM。 PowerShell 里用
New-Object System.Text.UTF8Encoding($false),否则中文会话会乱码。 - 只改
session_meta行。 会话正文里也可能出现model_provider字样,精确匹配"model_provider":"<旧值>"再替换。 - 不要再运行会乱改 Provider 标签的工具。 如果需要迁移 Provider,先查清目标环境的
default model provider,让标签值与之一致。
十、完整复现清单
- 准备:能访问
%USERPROFILE%\.codex,有sqlite3(或任意 SQLite 客户端)。 - 确认故障:
codex doctor输出里rollout DB model providers与default model provider不一致。 - 备份:按 7.1 步骤复制
state_5.sqlite、sessions\、session_index.jsonl、config.toml、auth.json。 - 停进程:结束 Codex app-server 和迁移工具进程。
- 改库:
UPDATE threads SET model_provider='openai' WHERE model_provider <> 'openai'; - 改文件:按 7.4 脚本把每个会话文件
session_meta的旧 Provider 替换成openai。 - 验证:
codex doctor中rollout DB model providers openai=<总数>,且rollout files and state DB thread inventory agree。 - 启动:打开 VS Code Codex 面板,历史列表应恢复。
十一、总结
这次“会话丢失”是典型的数据标签与应用预期不一致导致的显示问题,不是真的丢数据。排查时用好 codex doctor 和迁移工具自带的备份,就能快速定位根因;修复只需把 Provider 标签恢复到应用默认值,再让文件与索引保持一致即可。
文中所有路径、版本号、输出均来自 2026-08-07 在 Windows 10 + VS Code + Codex 扩展 26.803.41515 环境下的实测;不同版本/配置下 default model provider 可能不同,以你本机 codex doctor 的输出为准。
更多推荐



所有评论(0)