[Bug]: ctx_batch_execute timeout does not bound indexing/search, so Claude Code agents can hang for hours

Author: stgmtCreated Jul 10, 2026Updated Sep 17, 2026

Summary

ctx_batch_execute accepts a timeout parameter, but in practice it does not bound the whole MCP handler. In Claude Code, I observed ctx_batch_execute calls with timeout: 120000 remain in-flight for more than 4 hours after the command phase, apparently during context-mode indexing/search/formatting work against a bloated SQLite/FTS content DB.

Environment

  • context-mode: 1.0.169
  • Claude Code: 2.1.202
  • OS: Windows 11
  • storage: default ~/.claude/context-mode/content

Evidence from real Claude Code sessions

Three background agents were stuck around context-mode calls for hours:

agent-aee8e6d09a69e41c7 | ctx_search        | 2026-07-10T15:01:51Z -> 18:50:37Z | 228.8 min
agent-a5ba93371b699a949 | ctx_batch_execute | 2026-07-10T14:33:39Z -> 18:50:42Z | 257.1 min | call had timeout: 120000
agent-ae18a471c25b61a57 | ctx_batch_execute | 2026-07-10T15:02:27Z -> 18:51:51Z | 229.4 min

The project content DB at the time was heavily bloated:

content DB: 645,128,192 bytes
WAL:        349,454,312 bytes

Largest chunks persisted in chunks:

36,754,737 bytes | tracing and runtime observability evidence (2)
36,163,374 bytes | Visual and post-render artifact terminology (2)
35,988,924 bytes | Full current unstaged diff indexed for targeted queries

These huge chunks are related to #878, but this issue is specifically about timeout semantics: even if #878 is fixed, the tool should not be able to keep a Claude Code agent blocked forever.

Why timeout is misleading today

From source inspection, resolveExecTimeout may omit a timeout for Claude Code unless explicitly provided. When ctx_batch_execute does get a timeout, it appears to apply to command execution (runBatchCommands) but not necessarily to the later phases:

  • store/indexing
  • FTS/trigram search
  • fallback search
  • result formatting

Those later phases can be synchronous SQLite work. A JavaScript timer around only the command runner cannot interrupt a blocked synchronous DB/index/search path.

Expected

A ctx_batch_execute call with timeout: 120000 should either finish or return a timeout error in roughly 120 seconds. It should not remain in-flight for hours.

Actual

A ctx_batch_execute call with timeout: 120000 remained in-flight for about 257 minutes.

Suggested fixes

  1. Make timeout a hard wall-clock budget for the entire MCP handler, not just subprocess execution.
  2. Run DB/index/search/format phases in a killable worker process or otherwise make synchronous SQLite work interruptible.
  3. Add watchdog logging around each phase so users can see whether the call is blocked in command execution, indexing, FTS search, fallback search, or formatting.
  4. Add ctx_doctor checks for huge chunks, DB/WAL bloat, and stale in-flight sentinels.
  5. Combine this with #878: enforce max chunk size before FTS insert, so single-line/bundle/diff payloads cannot poison the DB.

Related issues

  • #878: Markdown chunker allows oversized single paragraphs / code blocks
  • #735: shared Claude Code KB / WAL contention under multi-session use
  • #559: indefinite hangs around ctx_search / WAL contention
  • #406: request for server-enforced timeout policy