From b124208fb920013e70a34f6aaea1d74a91838d05 Mon Sep 17 00:00:00 2001 From: Claude Dev Date: Thu, 12 Mar 2026 18:44:59 +0100 Subject: [PATCH] fix: Rate-Limit-Fehler der Claude CLI korrekt erkennen und loggen MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bisher wurde bei Exit Code 1 nur stderr gelesen, wodurch Rate-Limit-Meldungen auf stdout (als JSON) verloren gingen. Jetzt wird stdout zusätzlich geprüft und Rate-Limit-Fehler als [rate_limit] geloggt. Co-Authored-By: Claude Opus 4.6 --- src/agents/claude_client.py | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/src/agents/claude_client.py b/src/agents/claude_client.py index 661180d..3cae369 100644 --- a/src/agents/claude_client.py +++ b/src/agents/claude_client.py @@ -54,7 +54,12 @@ async def call_claude(prompt: str, tools: str | None = "WebSearch,WebFetch", mod if tools: cmd.extend(["--allowedTools", tools]) else: - cmd.extend(["--max-turns", "1"]) + cmd.extend(["--max-turns", "1", "--allowedTools", ""]) + cmd.extend(["--append-system-prompt", + "CRITICAL: You are a JSON-only output agent. " + "Output EXCLUSIVELY a single valid JSON object. " + "No explanatory text, no markdown fences, no continuation of previous responses. " + "Start your response with { and end with }."]) process = await asyncio.create_subprocess_exec( *cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE, @@ -76,8 +81,21 @@ async def call_claude(prompt: str, tools: str | None = "WebSearch,WebFetch", mod if process.returncode != 0: error_msg = stderr.decode("utf-8", errors="replace").strip() - logger.error(f"Claude CLI Fehler (Exit {process.returncode}): {error_msg}") - raise RuntimeError(f"Claude CLI Fehler: {error_msg}") + stdout_msg = stdout.decode("utf-8", errors="replace").strip() + + # Rate-Limit-Fehler kommen als JSON auf stdout, nicht auf stderr + error_type = "cli_error" + rate_limit_keywords = ["hit your limit", "rate limit", "resets", "rate_limit", "overloaded"] + combined_output = f"{error_msg} {stdout_msg}".lower() + if any(kw in combined_output for kw in rate_limit_keywords): + error_type = "rate_limit" + logger.warning(f"Claude CLI Rate-Limit (Exit {process.returncode}): {stdout_msg or error_msg}") + else: + logger.error(f"Claude CLI Fehler (Exit {process.returncode}): {error_msg}") + if stdout_msg: + logger.error(f"Claude CLI stdout bei Fehler: {stdout_msg[:500]}") + + raise RuntimeError(f"Claude CLI Fehler [{error_type}]: {stdout_msg or error_msg}") raw = stdout.decode("utf-8", errors="replace").strip() usage = ClaudeUsage()