[Bug]: Trace spans are never persisted on Windows - topicId "agent-session:<uuid>" leaks a ":" into the directory name, mkdir fails ENOENT

Author: mowenQWQCreated Sep 17, 2026Updated Sep 17, 2026

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 topicId is structurally formatted as agent-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

  1. 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.
  2. Extend assertSafeSegment to reject Windows-illegal characters in addition to traversal — cheap, platform-specific, prevents future misuse.
  3. 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 (traceTopicDirpath.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 topicId is structurally formatted as agent-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

  1. 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.
  2. Extend assertSafeSegment to reject Windows-illegal characters in addition to traversal — cheap, platform-specific, prevents future misuse.
  3. 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>,被直接用作目录名(traceTopicDirpath.join(traceRoot, topicId)),而 Windows 文件名不允许冒号,fs.mkdir 报 ENOENT。assertSafeSegment 只防了路径穿越、没防 Windows 非法字符。建议写/读路径统一做 topicId 转义,并在首次落盘失败时明确告警(当前为逐条 warn,极易忽略)。与 #20586/#20621 共用同一 topicId 命名。