Skip to content

CM-73909 fix resource tracker leak - #564

Merged
Ilanlido merged 5 commits into
mainfrom
CM-73909-fix-resource-tracker-leak
Oct 5, 2026
Merged

Ilanlido merged 5 commits into
mainfrom
CM-73909-fix-resource-tracker-leak

Conversation

@Ilanlido

@Ilanlido Ilanlido commented Oct 4, 2026

Copy link
Copy Markdown
Collaborator

Summary

On macOS, cycode ai-guardrails scan exits before its stdout reaches end-of-stream. Claude Code now treats that as a suspect capture ("its stdio went quiet before end-of-stream … refusing to honor the suspect capture"), so it discards the verdict and blocks the tool call, even though the CLI returned allow.

Cause: _perform_scan ran the scan in a multiprocessing.pool.ThreadPool to enforce a timeout. A ThreadPool only uses threads, but Pool.__init__ still creates a multiprocessing lock. When the start method is spawn (macOS) or forkserver (Linux on Python 3.14+), that lock starts a multiprocessing.resource_tracker process. The tracker inherits the hook's stdout and stderr, and by design it exits only after the parent does. In the frozen build, the tracker also runs the full CLI start-up again before it gets to the tracker code, so it holds the pipe for about 0.1–0.2s after the CLI exits.

Changes

  • Run the guardrails scan in a daemon thread. _perform_scan now uses a daemon threading.Thread and join(timeout) instead of a ThreadPool. This creates no multiprocessing lock, so no tracker starts. Timeouts still raise RuntimeError, exceptions from the scan are re-raised, and a hung scan still doesn't keep the process alive. ThreadPoolExecutor doesn't fit here, because its workers are joined when Python exits.
  • Import GitPython on first use. GitPython runs git version when it is imported. git_proxy imported it at module load, so every command paid for those subprocesses and about 150ms of import time, even commands that never use git. MCP and prompt hook events now start no git processes. File-read events still import GitPython, because they look up the repository's remote URL.

Notes

  • Windows is not affected: semaphores there are never registered with the resource tracker. The Linux release binary (Python 3.13, fork) is not affected today, but would be after a move to Python 3.14.
  • utils/scan_batch.py uses ThreadPool the same way. It is not on the guardrails path. Switching it to ThreadPoolExecutor would make Ctrl+C on a long scan wait for the batches already running, so it is left for a separate change.

Ilanlido and others added 2 commits October 3, 2026 16:35
ThreadPool creates a multiprocessing lock, which on macOS spawns a
resource_tracker process. The tracker inherits the hook's stdout and
exits only after the CLI does, so Claude Code sees the hook exit before
stdout reaches EOF, discards the verdict and blocks the tool call.

Run the scan in a daemon thread with a join timeout instead. A daemon
thread keeps the old timeout behaviour: a hung scan does not keep the
process alive.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
GitPython runs `git version` when it is imported. git_proxy imported
it at module load, so every command paid for git subprocesses and the
import (about 150ms), even commands that never touch git, such as
guardrails scans of MCP calls and prompts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Comment thread cycode/cli/apps/ai_guardrails/scan/handlers.py Outdated
Comment thread cycode/cli/apps/ai_guardrails/scan/handlers.py Outdated
Comment thread tests/cli/commands/ai_guardrails/scan/test_handlers.py Outdated
Ilanlido and others added 2 commits October 5, 2026 10:36
Move the scan worker to a module-level _run_scan that receives its
inputs through Thread args, and drop the narration comments.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Ilanlido
Ilanlido enabled auto-merge (squash) October 5, 2026 08:42
@Ilanlido
Ilanlido merged commit 367b0c3 into main Oct 5, 2026
28 checks passed
@Ilanlido
Ilanlido deleted the CM-73909-fix-resource-tracker-leak branch October 5, 2026 10:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants