适用场景:使用 Codex(VS Code 扩展 / 桌面应用)时,在「官方 ChatGPT 账号」与「第三方 Provider」之间切换登录,切换后发现会话历史列表完全为空,但本地数据其实还在。

本文基于一次真实故障排查记录编写,命令、路径、输出均来自本次实际操作。环境不同时请把路径和 Provider 名替换成你自己的。


一、问题现象

在 VS Code 的 Codex 面板里,会话历史列表完全为空,只能新建对话,看不到任何旧会话。

发生背景:

  1. 原来用官方 ChatGPT 账号登录 Codex,积累了从 2026-02-27 到 2026-08-01 的 215 个本地会话。
  2. 某天切换到第三方 Provider,并用了一个第三方小工具「Codex Provider History Fixer 0.2.1」迁移历史。
  3. 之后又切回官方 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.jssessionFiles.js 确认):

  1. 改数据前,先把 state_5.sqlitesessions\ 全量备份到 backups\provider-migration-<时间戳>\
  2. 执行 UPDATE threads SET model_provider = '<目标>' WHERE model_provider IN ('<源>')
  3. 逐个改写每个 sessions\**\*.jsonlsession_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|215integrity_checkok):

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

八、验证结果

  1. 再次运行 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
  1. 打开 VS Code 的 Codex 面板(触发 app-server 重新拉起),历史列表恢复显示全部旧会话,可正常点开继续对话。

本次实测两者都通过。

九、避坑总结

  1. 先确认数据还在,再动手恢复。 检查 state_5.sqlite 的线程数和完整性,别急着删重建。
  2. Provider 标签必须与应用默认 Provider 一致。 官方 ChatGPT 账号 + 默认配置下,codex doctor 报告的 default model provider 就是会话索引里该填的值(本机为 openai)。
  3. 迁移工具只改数据,不改配置。 所以“迁移到 chatgpt”之后,应用仍然按 openai 过滤,必然空列表。这是此类工具的固有坑。
  4. 改数据前必备份。 迁移工具自己都会先备份(backups\provider-migration-*),你手动改更应该备份。
  5. 改库前停进程。 先结束 Codex app-server 和迁移工具,避免锁库。
  6. 改 JSONL 用 UTF-8 无 BOM。 PowerShell 里用 New-Object System.Text.UTF8Encoding($false),否则中文会话会乱码。
  7. 只改 session_meta 行。 会话正文里也可能出现 model_provider 字样,精确匹配 "model_provider":"<旧值>" 再替换。
  8. 不要再运行会乱改 Provider 标签的工具。 如果需要迁移 Provider,先查清目标环境的 default model provider,让标签值与之一致。

十、完整复现清单

  1. 准备:能访问 %USERPROFILE%\.codex,有 sqlite3(或任意 SQLite 客户端)。
  2. 确认故障:codex doctor 输出里 rollout DB model providersdefault model provider 不一致。
  3. 备份:按 7.1 步骤复制 state_5.sqlitesessions\session_index.jsonlconfig.tomlauth.json
  4. 停进程:结束 Codex app-server 和迁移工具进程。
  5. 改库:UPDATE threads SET model_provider='openai' WHERE model_provider <> 'openai';
  6. 改文件:按 7.4 脚本把每个会话文件 session_meta 的旧 Provider 替换成 openai
  7. 验证:codex doctorrollout DB model providers openai=<总数>,且 rollout files and state DB thread inventory agree
  8. 启动:打开 VS Code Codex 面板,历史列表应恢复。

十一、总结

这次“会话丢失”是典型的数据标签与应用预期不一致导致的显示问题,不是真的丢数据。排查时用好 codex doctor 和迁移工具自带的备份,就能快速定位根因;修复只需把 Provider 标签恢复到应用默认值,再让文件与索引保持一致即可。


文中所有路径、版本号、输出均来自 2026-08-07 在 Windows 10 + VS Code + Codex 扩展 26.803.41515 环境下的实测;不同版本/配置下 default model provider 可能不同,以你本机 codex doctor 的输出为准。

Logo

AtomGit AI 社区提供模型库、数据集、Agent、Token等资源

更多推荐