[TaskList] Task store silently cleared mid-session; new ids resume past the gap

Status Open
Reported on v2.1.251
Maintainer reply None cached
Activity 1 comment · opened Aug 30, 2026

What's Wrong?

A session's entire task list silently disappears mid-session. TaskList returns "No tasks found" even though tasks were created earlier in that same session and none were ever deleted.

The on-disk store is ~/.claude/tasks/<session-id>/, holding one <id>.json per task plus a .highwatermark counter file. In the failure, every <id>.json is removed while .highwatermark is written with the last id issued. The two consequences:

  • TaskList enumerates the directory, finds nothing, and reports "No tasks found".
  • TaskCreate allocates from .highwatermark + 1, so new task ids resume after the vanished ones.

That second part is the distinctive fingerprint, and it is exact. Across 473 session directories on this machine, 7 show the truncated shape, and in every one the lowest surviving id equals .highwatermark + 1:

| session | surviving ids | .highwatermark |
|---|---|---|
| <session-A> | 263..290 | 262 |
| <session-B> | 5..8 | 4 |
| <session-C> | 31..33 | 30 |
| <session-D> | 23..31 | 22 |
| <session-E> | 30..50 | 29 |
| <session-F> | 10..19 | 9 |
| <session-G> | 17..27 | 16 |

The control group is equally sharp: every intact session directory has no .highwatermark file at all. Of 473 dirs, 396 still contain 1.json, and none of those sampled has the counter file. So .highwatermark appears to be written only by whatever clears the store — its presence is the fingerprint of the event.

Impact. Any workflow that mirrors a phase list into the task list loses its progress record mid-run. In my case a long multi-phase run lost all 22 of its tracked phases; the work itself was recoverable only because I also keep a file-based roadmap. A user relying on TaskList alone would silently lose the plan, and — because ids resume past the gap — nothing in the tool output signals that anything was lost.

What Should Happen?

Either the task store should not be cleared mid-session, or the clear should be observable: TaskList should be able to report that a prior set existed and was cleared, rather than being indistinguishable from a session that never created a task.

Error Messages/Logs

No error is emitted. TaskList simply returns:

No tasks found

The only on-disk trace is the orphaned counter:

$ ls -a ~/.claude/tasks/<session-D>/
.highwatermark  .lock  23.json  24.json  25.json ... 31.json

$ cat ~/.claude/tasks/<session-D>/.highwatermark
22

Steps to Reproduce

I could not identify the trigger, so I cannot give a deterministic recipe. What I can give is the observed sequence and, more usefully, four hypotheses I ruled out with evidence — hopefully narrowing the search:

  1. Run a long session that creates a substantial number of tasks via TaskCreate and drives them to completed.
  2. At some later point, TaskList returns "No tasks found".
  3. ls ~/.claude/tasks/<session-id>/ shows the <id>.json files gone and a .highwatermark present holding the last id issued.

Observed timeline in the session I investigated (timestamps from the session transcript, UTC):

| Time | Event | Task store |
|---|---|---|
| 08-28T07:43:12Z | context compaction | — |
| 08-28T07:44:30Z | TaskList | returned all 10 tasks ✅ |
| 08-30T01:46:39Z | TaskUpdate id=22 → completed | still live ✅ |
| 08-30T01:46:44Z | — | .highwatermark written (=22) |
| 08-30T01:47 → 06:01 | session idle ~4h15m | — |
| 08-30T06:13, 07:24, 07:57Z | three more compactions | — |
| 08-30T07:58:34Z | TaskList | "No tasks found" ❌ |

Ruled out — context compaction. This was my first hypothesis and it is wrong. A TaskList issued immediately after a compaction (08-28T07:44:30Z, ~78 s after the compaction at 07:43:12Z) returned the full list. Three compactions occurred before the loss window without clearing anything.

Ruled out — explicit deletion. Across 36 TaskUpdate calls in the transcript, the only statuses used were completed (24) and in_progress (12). There is no "status":"deleted" anywhere in the session.

Ruled out — a local scheduler. No crontab, no user LaunchAgents, no relevant launchd job, and no user hook referencing the tasks/ directory.

Ruled out — process restart / version change. The transcript records the same CLI version on all 2355 entries; there was no upgrade mid-session.

Not established — the trigger. .highwatermark was written 5 seconds after the final task reached completed, which suggests "clear once all tasks are completed". But I can falsify that directly: another session directory holds 7 tasks, all completed, uncleared, with no .highwatermark. So that is not the rule, and I would rather report the fingerprint than guess a cause.

If it helps, the hwm == lowest_surviving_id - 1 invariant holding 7/7, together with .highwatermark being absent from every uncleared directory, should make the clearing code path easy to locate from the write site of that file.

Claude Code Version

2.1.251 (Claude Code) is what claude --version reports now. The session in which the loss was observed recorded version 2.1.245 on every transcript entry; the CLI has since been updated.

Platform

macOS (Darwin 25.5.0, arm64; macOS 26.5.2).

Is this a regression?

Not sure — I have no earlier known-good comparison. The affected session directories on this machine span 08-07 to 08-30, so the behaviour is not new as of the current version.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗