Repository navigation
sessions: v0.1.1291 quits at start with "panic: close of nil channel" in refresh's publish #2932
Description
What happens
After updating to v0.1.1291 (macOS arm64, Darwin 25.5), magpie quits every time a few seconds after start. It reproduces on every launch. Going back to v0.1.1290 fixes it: that build has been running normally on the same data.
Run from a terminal, the binary exits with status 2:
panic: close of nil channel
goroutine 103 [running]:
github.com/yetone/magpie/internal/sessions.refresh.func5(...)
github.com/yetone/magpie/internal/sessions/sessions.go:886
github.com/yetone/magpie/internal/sessions.refresh(...)
github.com/yetone/magpie/internal/sessions/sessions.go:900 +0xe08
github.com/yetone/magpie/internal/sessions.statsIn(0x0, ...)
github.com/yetone/magpie/internal/sessions/stats.go:143 +0x430
github.com/yetone/magpie/internal/sessions.StatsAndNative(0x0)
github.com/yetone/magpie/internal/sessions/stats.go:117 +0x68
github.com/yetone/magpie/internal/gui.combinedSessionStats(0x0)
github.com/yetone/magpie/internal/gui/sessions.go:466 +0x48
github.com/yetone/magpie/internal/gui.statsFor(...)
github.com/yetone/magpie/internal/gui/sessions.go:443 +0x2ac
github.com/yetone/magpie/internal/gui.warmSessions.func1.1.warmSteps.1()
github.com/yetone/magpie/internal/gui/sessions.go:507 +0x20
github.com/yetone/magpie/internal/gui.warmUp(...)
github.com/yetone/magpie/internal/gui/sessions.go:529 +0x38
github.com/yetone/magpie/internal/gui.warmSessions.func1.1()
github.com/yetone/magpie/internal/gui/sessions.go:497 +0x50
github.com/yetone/magpie/internal/sessions.Warm(...)
github.com/yetone/magpie/internal/sessions/quiet.go:31 +0x94
github.com/yetone/magpie/internal/gui.warmSessions.func1()
github.com/yetone/magpie/internal/gui/sessions.go:497 +0x30
created by github.com/yetone/magpie/internal/gui.warmSessions in goroutine 1
github.com/yetone/magpie/internal/gui/sessions.go:493 +0x50
Where it seems to come from
The panic is close(parsing[j.f.path]) in refresh's publish (sessions.go:886 at v0.1.1291). The parsing map arrived with c381e4c ("a read is never held by another read's refresh…", #2776), which is in 1291 and not in 1290.
For parsing[path] to be nil at publish time, its entry has to be deleted already. As far as I can see, only publish deletes entries. So probably the same path is published twice: either it is in todo twice in one refresh (the parsing[f.path] != nil check runs before any entry is set, so a duplicate in want gets past it and its channel is overwritten), or another refresh published it in between. I could not tell which file triggers it. A rough re-implementation of the listings for the agents on this machine found no duplicate paths, but that was not the real allFiles(). Agents with sessions here: Claude Code, Codex (incl. .jsonl.zst in archived_sessions), Grok, WorkBuddy, CodeBuddy Code, Pi, Cursor (agent-transcripts only), dsh, and Hermes (root state.db plus one named profile).
A guard against a duplicate path in todo (or publish skipping a nil channel) would at least keep the warm-up from taking the whole app down.
Activity
JoeyWu-tech commentedon Oct 19, 2026
我在看这个。去重的兜底先做上,同时在找重复的 path 是哪个列表给的,有结果了发上来。
JoeyWu-tech commentedon Oct 19, 2026
跟你猜的一样,是一次 refresh 里同一个 path 出现了两次。refresh 挑要读的文件时会先查
parsing[f.path],但这个条目要到后面建 job 时才设,所以重复的 path 两次检查都能过,变成两个 job 共用一个条目。第一个 publish 把它 close 掉并删了,第二个再 close 拿到的就是 nil,也就是你贴的 886 那行。改法是挑文件的时候就把条目设上,第二次出现的就会被挡住。加了个测试,在 main 上跑出来就是你这个 panic(886 / 900),改完通过。
分支:https://github.com/JoeyWu-tech/magpie/tree/fix/2932-refresh-dup
(两个 commit,
fbd99cb和b4e9e20,baseab7ec8c,patch sha25619933ae3f1bbb2633100196dd80758b62b13c205f1105971498eb4678c751740,用的是git format-patch --stdout ab7ec8c..b4e9e20 | sha256sum)不过到底是哪个列表给了重复的 path,我没找到,每个 agent 自己的列表都按 path 去重了。我能想到的是两个 agent 的目录指到了同一个地方,比如
PI_CODING_AGENT_DIR设成了~/.omp/agent,或者CODEBUDDY_CONFIG_DIR和WORKBUDDY_CONFIG_DIR是同一个目录。你那边有设过类似的变量吗?另外顺手修了个小的:sessions 包开
-race跑的话,TestManageReadsOnlyTheAgentsItShows在 main 上就是红的,测试里数解析次数用的是普通 int。CI 的 race 不跑这个包,所以一直没暴露。我单独放在fbd99cb,排在主修复前面,不需要的话跳过它就行。全量测试和其他检查的结果都写在 commit 里了。
TimWongUp commentedon Oct 19, 2026
有,就是你猜的第二种。我的
~/.zshrc里有一行:所以
CodeBuddyDir()和WorkBuddyDir()都是~/.workbuddy,codebuddyFiles()和workbuddyFiles()会把~/.workbuddy/projects下同一批.jsonl各列一遍(一个算codebuddy:,一个算workbuddy:)。allFiles()直接拼起来,所以want里同一个 path 有两条。其他目录变量都没设,~/.omp也不存在。谢谢这么快就修了。这样的话,除了 refresh 里的兜底,可能还要看一下:两个 buddy 共用一个目录的时候,会话会不会在列表和统计里各算一遍。
sessions: CodeBuddy Code kept in WorkBuddy's folder is read once, as …
JoeyWu-tech commentedon Oct 19, 2026
谢谢确认,这下对上了。你说的重复计算也是真的,我拿测试数据按你这行配置跑了一下:会话页上 WorkBuddy 的 3 个会话又以 CodeBuddy 的名义多列了一遍,用量那边则把这些调用全算到了 CodeBuddy 头上,两个页面连 agent 都对不上。
在同一个分支上加了一个 commit
3b9b094:CodeBuddy 的目录如果就是 WorkBuddy 的目录(软链接也算),就只按 WorkBuddy 读一遍,会话页、用量、统计都一样,"会话从哪些目录读取"那里也只显示一次。有个取舍要说一下:从文件本身看不出是哪个工具写的,所以这个目录下的会话都算 WorkBuddy 的。用 CodeBuddy CLI 在里面开的会话,也会显示成 WorkBuddy、按 WorkBuddy 的方式恢复。目录本来是 WorkBuddy 的,那个变量只是把 CLI 挪过去了,所以我选了这边。如果你更希望反过来,告诉我一声。
现在三个 commit 的 patch sha256 是
1bbff1f7a30ed094e1b1d53eeaa2a4dd4acb46c25f00700a430a824a03e90319(git format-patch --stdout ab7ec8c..3b9b094 | sha256sum),测试记录照旧写在 commit 里。TimWongUp commentedon Oct 19, 2026
按 WorkBuddy 算就行,我这边没问题。
那个变量是我当初为了让 CodeBuddy CLI 跟 WorkBuddy 共用一套配置加的,目录本来就是 WorkBuddy 的,归到它名下说得通。CLI 开的会话显示成 WorkBuddy、按 WorkBuddy 的方式恢复,我这边能接受。
等合进 main 发了新版我就升上去,跑一下再回来说一声。谢谢,修得挺快的。
nativeas commentedon Oct 19, 2026
我这边在 v0.1.1292 仍然遇到了相同的启动退出问题,补充一份复现信息。
环境
复现与实际表现
/Applications/magpie.app。/Applications/magpie.app/Contents/MacOS/magpie,也复现了退出,退出码为 2,捕获到下面的 panic。预期是应用启动后保持运行。
崩溃日志
上面省略了调用参数中的内存地址。panic 之前还有一条 Gemini 登录失效提示:
目前没有确认这条提示与 panic 有关,也尚未验证本机是否存在上文提到的重复会话目录配置。尚未回退版本或测试补丁。
JoeyWu-tech commentedon Oct 19, 2026
@nativeas 1292 里还没有这个修复,补丁在我上面贴的分支上,等合进 main。
方便的话帮忙看一下
~/.zshrc(或者你用的 shell 配置)里有没有设CODEBUDDY_CONFIG_DIR、WORKBUDDY_CONFIG_DIR这类变量,指到同一个目录:如果有,先把那行注释掉再启动就能绕过去。如果什么都没有,说明还有别的地方会把同一个文件列两次,我再接着查。补丁里的兜底两种情况都能挡住,只是想确认原因有没有找全。
Gemini 那条应该没关系:崩的是启动时统计会话那一步,它不读 Gemini 的文件,那条只是 Gemini 账号登录过期的提示。
nativeas commentedon Oct 19, 2026
@JoeyWu-tech 谢谢说明。我这边检查了:
~/.zshrc和~/.zprofile中,没有找到CODEBUDDY_CONFIG_DIR、WORKBUDDY_CONFIG_DIR、PI_CODING_AGENT_DIR或OMP_CODING_AGENT_DIR的设置。~/.zshenv、~/.bashrc和~/.bash_profile不存在。所以目前没有找到你提到的共用目录变量,尚不能确认本机是通过哪种路径触发了重复读取。暂时没有修改 shell 配置,也没有测试分支补丁。
我会等包含修复的官方 macOS 版本发布后再更新验证。如果还需要检查特定目录、软链接或其他信息,麻烦告诉我具体检查项,我再补充结果。谢谢!
JoeyWu-tech commentedon Oct 19, 2026
谢谢帮忙查,那应该是别的变量,我上次列得太少了。能挪会话目录的变量其实有十几个,而且桌面版的环境是从登录 shell 借来的,所以用登录 shell 查一遍最准,间接加载的脚本也会算进去:
第二条是 Pi 的会话目录设置,它也能把别的 agent 的文件夹算进来。输出里只有路径,没有密钥。
要是两条都什么也没打出来,麻烦说一下你装了哪些 agent,我照着目录再排查。
nativeas commentedon Oct 19, 2026
@JoeyWu-tech 按你补充的方法又检查了一遍:
zsh -lic登录交互式 shell 中运行env,筛选你列出的全部目录变量,没有任何匹配输出。~/.pi/agent/settings.json不存在,所以该文件里也没有可检查的sessionDir设置。另外补充 agent 信息:在同样的登录 shell 中,通过
command -v确认可找到的 CLI 有 Claude Code、Codex、Gemini CLI、Hermes。也检查了
pi、omp、qoder、codebuddy、workbuddy、grok、kimi、dsh、droid、cursor-agent、cline和opencode,这些命令在该 shell 的 PATH 中都没有找到。这只是 PATH 检查结果,尚不能排除其他安装位置或旧的会话目录残留。目前仍未修改目录配置或测试分支补丁。如果需要进一步核对默认目录、软链接或残留会话文件,请告诉我具体检查项,我再补充。谢谢!
JoeyWu-tech commentedon Oct 19, 2026
@nativeas 辛苦了,查得很细。这样看你机器上确实没设什么变量。你装的这几个 agent 我又对着代码过了一遍,Claude Code、Codex、Hermes 列文件时都会先去重,暂时没找到能把同一个文件列两次的地方,这个只能先留着。
不过不影响修复:分支上的改动是 refresh 拿到一个文件就先占上,同一个路径不管从哪儿多冒出来一次都只读一遍,所以不管来源是什么都不会再崩。
等新版出来你升上去以后,如果看到会话页里同一个会话出现两次,或者用量像是翻了倍,在这儿说一声就行,我再按那个会话倒着查。
tianhao2316-beep commentedon Oct 20, 2026
补充一个 Windows 上的同类复现,崩溃栈与本 issue 一致。
环境与复现
warmSessions -> StatsAndNative -> refresh调用链。[WebView2] Environment created successfully。回退验证
备份后,保留现有账户、模型配置和原始会话文件,将程序替换为官方 0.1.1290,并设置
noAutoUpdate=true防止自动升级回去。下载文件已与官方SHA256SUMS核对一致。回退后已实际打开会话页面,成功加载 751 个 Codex 会话;截至本次检查已连续运行约 7 分钟,窗口正常响应,启动日志未再出现 panic。
目前尚未确认本机是哪份会话文件/目录被重复枚举,未测试本 issue 中的修复分支,也未在本机测试 0.1.1294。因此这里只补充 0.1.1293 的 Windows 复现与 0.1.1290 的回退结果。
崩溃日志
以下省略了调用参数中的内存地址,函数名和源码行号保留:
nativeas commentedon Oct 20, 2026
@JoeyWu-tech 这边找到另一个具体的重复路径来源了:Hermes 的同一个 SQLite 数据库里,有两条字节内容相同的 session ID,一条以 TEXT 存储,另一条以 BLOB 存储。 不需要配置共用目录或设置环境变量也能触发。
以下已脱敏,不包含真实 session ID、本地路径、聊天内容、账号或数据库附件。
发现与源码分析
sessions.id声明为TEXT PRIMARY KEY,但数据库里实际同时存在 TEXT 和 BLOB 两种存储类型的同名 ID。PRAGMA quick_check返回ok,所以这并非该检查能发现的数据库结构损坏。hermesFiles()把id扫描到 Gostring;TEXT 和包含相同字节的 BLOB 都变成同一个字符串,因此生成相同的虚拟路径<hermes-db>#<session-id>。refresh标记parsing[path]前进入待处理列表。后面共用/覆盖同一个 channel 条目,第一个 publish 关闭并删除它,第二个 publish 就在sessions.go:886执行close(nil)。这与本机实际 panic 栈一致。对照实验(官方 macOS arm64 v0.1.1294)
HERMES_HOME指向空目录HERMES_HOME指向原数据库的一致性副本这些是本地读取实际历史的隔离实验,不是修改 Magpie 源码后的测试。
已验证的本地绕过结果
完整备份并校验数据库后,进一步检查了异常 BLOB ID:消息表、用量表及已检查的 session 关联字段中没有对该 BLOB ID 的精确引用。仅移除这一条异常 BLOB session 记录,保留正常 TEXT session;其关联消息数量在事务前后完全一致。
随后安装官方 v0.1.1296,实际连续运行超过 90 秒,并打开会话页面成功加载 Hermes 会话,没有再出现该 panic。
这只证明本机数据绕过有效:没有在修复原始数据前单独验证 v0.1.1296,也没有测试你提供的修复分支,不能据此认定上游问题已修复。 异常 BLOB 行最初是如何写入的仍未知。这里也不建议其他用户照搬删除操作,其他数据库可能有不同的关联数据。
无隐私数据的最小 SQLite 示例
下面只操作内存数据库,能演示为什么声明了 TEXT 主键仍会出现两条归一化后相同的 ID;它不是完整的 Magpie 崩溃回归测试:
可以把这种 TEXT/BLOB 混合 ID 的情况加入 Hermes 列表或
refresh去重的回归用例。即使异常数据来源尚未查清,归一化后的相同虚拟路径也不应让整个应用退出。sessions: a session id stored as TEXT and as BLOB is read once (yeton…
8 remaining items
JoeyWu-tech commentedon Oct 21, 2026
@mxl2498 谢谢,堆栈和绕过方法都很有用,
--gateway也会崩这点我之前没注意到。小更正一下 commit 号:
fbd99cb那个 main 已经自己合了(9afdeb89),所以我把分支 rebase 了,现在是fix/2932-rebased上三个 commit,头是7cc938ca,内容就是你说的那三处修复。两个变量指向同一个.workbuddy的情况我昨天按 @Tsuki-hash 的环境单独测过,分支上每个会话只算一次,main 上就是你这个 panic。刚又核了一遍,现在的 mainba319a75上能直接打。cunnak commentedon Oct 21, 2026
Another Windows data point — and a slightly different trigger vector than the installer-written variables reported above.
Repro (100%, every launch): magpie-windows-amd64.exe, v0.1.1307 and v0.1.1308, Windows 11. Panic ~4-5s after start, exit code 2, identical stack to this issue (
refresh.func5→ sessions.go:889, warmSessions → sessions.Warm → StatsAndNative → refresh). Happens in bothmagpie weband GUI mode.Trigger on this machine:
CODEBUDDY_CONFIG_DIRandWORKBUDDY_CONFIG_DIRare both set to the same directory (C:\Users<user>.workbuddy) — but unlike the installer-written case, these are injected at runtime by the WorkBuddy/CodeBuddy IDE host process into its child processes. The User and Machine registry scopes are both empty, so any app launched from the IDE's integrated terminal inherits the collision even on machines where no installer wrote these variables. CodeBuddyDir() == WorkBuddyDir() → the same .jsonl sessions listed twice → duplicate path → close(nil channel), exactly as analyzed above.Verified workarounds:
CODEBUDDY_CONFIG_DIR(empty value) before launch makes v0.1.1307 AND v0.1.1308 start and serve the gateway normally (127.0.0.1:3425 → 200, /v1/models returns the model list). This is the cheapest fix for affected users.MAGPIE_NO_ACCOUNTS=1does NOT help — the panic is unrelated to account discovery.Also confirming: plain CLI commands (
magpie ls,magpie providers,magpie update, …) never panic in the same poisoned environment — only the GUI/web/tray startup path goes through the session warm-up.Since the dedup patch on
fix/2932-rebasedwould presumably cover this vector too, posting in case it helps push the merge. The runtime-injection angle may be worth a line in the release notes when it ships, since Windows users hitting this won't find anything in their registry to clean up. Happy to provide more logs if useful.JoeyWu-tech commentedon Oct 21, 2026
@cunnak thanks, the IDE-injected angle is a good catch. That one would leave people with nothing to clean up in the registry.
Yes, the branch covers it. The fix doesn't care where the variables come from: it dedupes by the folder itself (os.SameFile), so two settings pointing at one
.workbuddyget read once whether an installer wrote them or the IDE host passed them down. I tested that exact state yesterday (both vars on one moved folder): one session each on7cc938ca, the same panic on main. Still applies cleanly to today's mainf5b01574.Tsuki-hash commentedon Oct 21, 2026
@mxl2498 谢谢这份 Windows 复现,
web --gateway那条我这边也当成覆盖面的补充记下了。有一个前提要更正一下,免得后面看的人照着查错方向:main 里没有
MAGPIE_NO_SESSIONS这个开关。 我把internal/下所有MAGPIE_*环境变量扫了一遍,只有MAGPIE_NO_ACCOUNTS(只关账号发现,internal/provider/discovery.go)和MAGPIE_NO_STATS(只关遥测/partner 事件,internal/stats/stats.go),没有NO_SESSIONS。所以MAGPIE_NO_SESSIONS=1不起作用不是漏洞,是它不存在;MAGPIE_NO_ACCOUNTS=1对这条 panic 无效也是对的,因为它本来就不碰会话预热。顺带把
--gateway说清楚:gui.warmSessions()是启动 3 秒后无条件go出来的(internal/gui/sessions.go),不看web/--gateway/ GUI 哪种模式,所以只要那个进程活着就会走进StatsAndNative -> refresh。换句话说,--gateway崩不是第二个 bug,是同一条路径的另一个入口,fix/2932-rebased三个 commit 一起就都盖住了。如果以后想给“会话读取”一个真正的开关(跳过预热/只读缓存),那是独立的功能请求,跟 #2932 这个修复拆开提更合适,别吊在同一个 issue 上等。
sessions: a path listed twice in one read is read once, so the start'…
budget: a window two limits share counts a call once (#2942)
yetone commentedon Oct 22, 2026
Landed on main in 572a175, built on @JoeyWu-tech's fix/2932-rebased (7cc938c) and credited to him as co-author.
CODEBUDDY_CONFIG_DIRpoints at WorkBuddy's folder (the same path, a link, or a different letter case on Windows), those sessions are read once, as WorkBuddy's. The folder is also shown once under the session folders.state.dbthat holds one id as a TEXT row and a BLOB row (@nativeas's case) gives one session. OpenCode lists such an id once too.Tests:
close of nil channel, both on macOS and on a Windows 11 box. The case where both variables point at one folder (as for @Tsuki-hash and @mxl2498) goes throughStatsAndNative, the warm-up's own call.internal/sessionspackage passes on Windows.Not tried yet: a real WorkBuddy or Hermes install, and starting the app on Windows. @TimWongUp, @tianhao2316-beep, @cunnak, @Tsuki-hash, @mxl2498, @nativeas: once a release includes it, please check that magpie stays up after it starts. I'm keeping this open until you confirm.
Not fixed here: Pi/omp and Qoder/Qoder CN sharing one folder under different spellings are still listed twice, though they no longer crash. That is #3258.
agent, gateway: a Claude model magpie can only ask translated no long…
sessions: a published parse closes its own channel, not the map's
JoeyWu-tech commentedon Oct 22, 2026
谢谢 @yetone 收了,测试也补得比我全。
@nativeas 说好的:修复(572a1757)从 v0.1.1320 开始就带上了,现在最新是 v0.1.1322。装上以后启动看看还会不会退出,有问题在这儿说一声。
mxl2498 commentedon Oct 23, 2026
@yetone 按你的要求,在 Windows 11 + 真实 WorkBuddy 安装 环境下完整验证过了,修复确认生效,可以从我这边结掉这个 issue。
环境
magpie-windows-amd64.exe(桌面/GUI 版),同时跑tray常驻实例 + 一个独立的web进程修复前(0.1.1306 / 0.1.1307)
打印出地址后几秒内进程退出,
panic: close of nil channel,栈在sessions.go:889/sessions.go:903(refresh → publish),3430 端口始终起不来。当时的触发条件是这两个变量指向同一目录:
补充一点:User / Machine 两个作用域里查都是空的,说明不是安装器写进注册表/用户变量的,而是 WorkBuddy 桌面端启动子进程时注入的——所以 Windows 上中招的人翻系统设置是找不到的(和 @cunnak 那条 IDE 注入的观察一致)。
当时靠
CODEBUDDY_CONFIG_DIR= magpie web --lan绕过。修复后(0.1.1325 → 0.1.1327)
升级后直接跑同一条命令,不动任何环境变量:
0.0.0.0:3430正常监听magpie web --gateway --lan --no-open同样不再崩——之前我以为是另一处,确认是同一条路径一起被盖住了另外提一句:更新到 0.1.1327 时旧的 web 进程被重启掉了(更新程序会接管重启),重新拉起即可,不是回归。
更正我上一条的一处说法
MAGPIE_NO_SESSIONS=1是我写错了——main 里没有这个变量(如 @Tsuki-hash 所说,只有MAGPIE_NO_ACCOUNTS和MAGPIE_NO_STATS)。它不是"无效",是根本不存在,当时真正起作用的只是清空CODEBUDDY_CONFIG_DIR那一步。现在连这一步也不需要了。辛苦 @JoeyWu-tech 和 @yetone,从报上去到修完两天不到,速度很顶。
JoeyWu-tech commentedon Oct 23, 2026
@mxl2498 谢谢用真实的 WorkBuddy 环境跑了一遍,这个是我们这边一直没法测的,
--gateway也一起确认了正好。sessions: a path listed twice in one read is read once, so the start'…
budget: a window two limits share counts a call once (yetone#2942)
agent, gateway: a Claude model magpie can only ask translated no long…