[Bug]: Trace spans are never persisted on Windows - topicId "agent-session:<uuid>" leaks a ":" into the directory name, mkdir fails ENOENT
This issue was translated automatically.
Environment
- Cherry Studio 2.0.14 (packaged build)
- Windows 11 Home China x64
Symptom
Agent-session trace spans are never written to disk. The trace root folder stays empty even after days of agent use. The log repeatedly shows:
{"level":"warn","message":"Failed to save trace spans","err":{"code":"ENOENT","path":"<traceRoot>/trace/agent-session:2fcbb157-516e-4b2f-9ca1-8d0e875f30f4","syscall":"mkdir"}}
Root cause
TraceFlushListener.saveSpans(topicId) → TraceStorageService.writeTraceFile(topicId) → traceTopicDir(topicId):
private traceTopicDir(topicId: string): string {
this.assertSafeSegment(topicId, 'topicId') // guards path traversal only
return path.join(this.traceRootDir(), topicId)
}
fs.mkdir(dir, { recursive: true }) then fails on Windows with ENOENT, because : is not a legal character in NTFS directory names. Reproducer: mkdir colon-test:abc → "The filename, directory name, or volume label syntax is incorrect." assertSafeSegment rejects ../ traversal but does not reject Windows-illegal filename characters (\ : * ? " < > |).
Where it bites
- Agent-session
topicIdis structurally formatted asagent-session:<uuid>— the colon is not user input, it is the topic naming scheme itself. - Persistence fails silently, so the Trace pane has no history for agent sessions; AI-trace observability for agents is effectively disabled on Windows.
- Same topicId naming family as #20586 / #20621 (
agent-session:…), so this also hampers debugging those flows.
Expected behavior
Agent-session trace spans persist on Windows like any other topic; or the failure surfaces clearly (today it is a per-event warn that is easy to miss).
Suggested fix
- Sanitize/encode the topicId used as a directory segment on the write path, and reuse the exact same mapping on the read path — e.g. replace
:(and other illegal chars) with-or percent-encoding. - Extend
assertSafeSegmentto reject Windows-illegal characters in addition to traversal — cheap, platform-specific, prevents future misuse. - Consider logging a loud once warning on the first persist failure, since a per-event warn is invisible in practice.
Related
- #17189 "Trace functionality completely unusable in Agent mode" — auto-closed as
not_planned(never fixed); still reproducible on 2.0.14, different root cause. - #20586 / #20621 share the
agent-session:topicId naming.
Chinese Summary: Agent session traces are never persisted to disk on Windows. The root cause is that topicId takes the form agent-session:<uuid>, which is directly used as a directory name (traceTopicDir → path.join(traceRoot, topicId)), but Windows filenames don't allow colons, causing fs.mkdir to fail with ENOENT. assertSafeSegment only guards against path traversal, not Windows-illegal characters. It's recommended to sanitize topicId consistently on both write/read paths, and to emit a clear warning on first persistence failure (currently it's a per-event warn that's easily overlooked). Shares the same topicId naming with #20586/#20621.
Original Content
Environment
- Cherry Studio 2.0.14 (packaged build)
- Windows 11 Home China x64
Symptom
Agent-session trace spans are never written to disk. The trace root folder stays empty even after days of agent use. The log repeatedly shows:
{"level":"warn","message":"Failed to save trace spans","err":{"code":"ENOENT","path":"<traceRoot>/trace/agent-session:2fcbb157-516e-4b2f-9ca1-8d0e875f30f4","syscall":"mkdir"}}
Root cause
TraceFlushListener.saveSpans(topicId) → TraceStorageService.writeTraceFile(topicId) → traceTopicDir(topicId):
private traceTopicDir(topicId: string): string {
this.assertSafeSegment(topicId, 'topicId') // guards path traversal only
return path.join(this.traceRootDir(), topicId)
}
fs.mkdir(dir, { recursive: true }) then fails on Windows with ENOENT, because : is not a legal character in NTFS directory names. Reproducer: mkdir colon-test:abc → "The filename, directory name, or volume label syntax is incorrect." assertSafeSegment rejects ../ traversal but does not reject Windows-illegal filename characters (\ : * ? " < > |).
Where it bites
- Agent-session
topicIdis structurally formatted asagent-session:<uuid>— the colon is not user input, it is the topic naming scheme itself. - Persistence fails silently, so the Trace pane has no history for agent sessions; AI-trace observability for agents is effectively disabled on Windows.
- Same topicId naming family as #20586 / #20621 (
agent-session:…), so this also hampers debugging those flows.
Expected behavior
Agent-session trace spans persist on Windows like any other topic; or the failure surfaces clearly (today it is a per-event warn that is easy to miss).
Suggested fix
- Sanitize/encode the topicId used as a directory segment on the write path, and reuse the exact same mapping on the read path — e.g. replace
:(and other illegal chars) with-or percent-encoding. - Extend
assertSafeSegmentto reject Windows-illegal characters in addition to traversal — cheap, platform-specific, prevents future misuse. - Consider logging a loud once warning on the first persist failure, since a per-event warn is invisible in practice.
Related
- #17189 "Trace functionality completely unusable in Agent mode" — auto-closed as
not_planned(never fixed); still reproducible on 2.0.14, different root cause. - #20586 / #20621 share the
agent-session:topicId naming.
中文摘要:Agent 会话的 trace 在 Windows 上从未落盘。根因是 topicId 形如 agent-session:<uuid>,被直接用作目录名(traceTopicDir → path.join(traceRoot, topicId)),而 Windows 文件名不允许冒号,fs.mkdir 报 ENOENT。assertSafeSegment 只防了路径穿越、没防 Windows 非法字符。建议写/读路径统一做 topicId 转义,并在首次落盘失败时明确告警(当前为逐条 warn,极易忽略)。与 #20586/#20621 共用同一 topicId 命名。
Source: CherryHQ/cherry-studio