Skip to content

[BUG] Stop:Callback loops forever on stale in_progress task from unrelated project/session — persists across compaction and process restart #935

Description

@Sero-Sen-Games

Related issues

This looks like the same bug family as #852, #493, #513, and #624, but with a
different trigger than any of them — worth checking whether hasRunningSubagents()
(named in #852) also consults on-disk task state under ~/.claude/tasks/, not just
the in-memory activeAsyncSubagents/pendingAsyncSubagents maps that #493/#852
discuss.

Summary

Stop:Callback fired continuously for ~2.5 hours, blocking turn completion with:

Background subagents are still running. Use TaskOutput task_id="..." block=true
to wait for their results before ending your turn.

TaskList and TaskOutput(block=true) both confirmed zero live background tasks
throughout, on every attempt. The false signal survived a context-compaction event
and a full kill of the underlying OS process. Root cause traced to a stale,
unrelated task record left in in_progress state from a different project,
over three weeks earlier
— the check behind Stop:Callback appears to treat "any
task anywhere under ~/.claude/tasks/ with status: in_progress" as "a subagent is
currently running," with no scoping to the current session, project, or actual live
process/task-ID state.

Environment

  • Claudian (Obsidian plugin), engine version 2.1.209, entrypoint: sdk-ts
  • OS: Windows
  • Session file: faf39593-3157-448f-ad56-f34cc6e0ea84.jsonl

Timeline (UTC, from the session transcript)

  1. 16:29 — Grading workflow starts; coordinator launches 10 background
    subagents via Agent(run_in_background: true).
  2. 16:51:53 — Stop hook fires once, correctly: "Background subagents are
    still running." Claude calls TaskOutput for the two still-running agents
    (Ormond, Thompson) as instructed. Resolves normally in a single turn — this
    firing is not part of the later loop.
  3. 17:03:12 — Auto-compaction triggers (preTokens: 189128) while 2 subagents
    are still finishing.
  4. 17:08:21 → 17:22:43 — First loop burst: 30 consecutive identical
    stop_hook_summary events, ~29s apart:
   {"type":"system","subtype":"stop_hook_summary","hookCount":2,
    "hookInfos":[{"command":"powershell ... stop-hook.ps1"},{"command":"callback"}],
    "hookErrors":["Background subagents are still running. Use `TaskOutput task_id=\"...\" block=true` to wait for their results before ending your turn."]}
  1. TaskList repeatedly returns "No tasks found"; direct inspection of the
    coordinator process's live children shows none alive. False positive confirmed.

  2. 18:50:23 → 18:51:19 — Second, tighter burst: 13 firings in <1 minute
    (~4.3s apart).

  3. User kills the coordinator process (PID 64468). Claudian auto-relaunches a
    new process (PID 50024)
    , resumes the same session state — the stuck flag
    returns immediately, proving it's not tied to the OS process or in-memory state.

  4. Located ~/.claude/tasks/01253de0-dce6-4346-a798-89ca4b5f1b4a/1.json:

    {
      "id": "1",
      "subject": "Complete HTML to Markdown conversion audit and repair",
      "status": "in_progress",
      ...
    }

    Dated June 18 — over 3 weeks before this incident — from an unrelated
    project (Roll20/D&D campaign markdown conversion, not the grading job in
    question). An empty .lock file sits alongside it, also dated June 18.

  5. Transcript ends here; user force-killed the process again shortly after to
    break the loop for good.

Evidence ruling out user-configured hooks

~/.claude/settings.json registers exactly one Stop hook — a PowerShell toast
notifier (async: true), which never inspects task state and cannot inject
blocking feedback. Its text never matches the repeating error. Verified
independently across the whole incident.

Impact

  • ~2.5 hours of session time consumed across two hard loop bursts
  • Not resolvable from within the session — no tool exposes which task record is responsible; required manual filesystem digging under ~/.claude/tasks/
  • Survives context compaction
  • Survives killing and relaunching the process
  • Will recur on any future session, any project, for as long as any stale
    in_progress task record exists anywhere in ~/.claude/tasks/

Suggested fixes

  1. Scope whatever hasRunningSubagents() (or its on-disk equivalent) checks to
    the current session/project, not any in_progress record anywhere on disk.
  2. Add a staleness/TTL check — a task untouched for weeks shouldn't count as
    "currently running."
  3. Have the hook's error text include the actual task/agent ID it thinks is
    running (currently a literal "..." placeholder), so users can self-diagnose
    instead of manually searching ~/.claude/tasks/.
  4. Since killing+relaunching the process didn't clear it, whatever persists this
    flag should be reset on relaunch, or at least be clearable via a slash command.

Workaround applied

Manually edited ~/.claude/tasks/01253de0-dce6-4346-a798-89ca4b5f1b4a/1.json,
setting status from in_progress to completed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions