Skip to content

bug: detection job silently passes when Claude Code CLI exits with code 1; 429 rate-limit not classified as rate-limit error #31073

@yskopets

Description

@yskopets

Summary

Two related bugs observed in the detection job when Claude Code CLI fails due to a rate-limit (429) error:

  1. The 429 is not classified as a rate-limit error — the harness logs isRateLimitError=false even though the Claude Code result JSON clearly contains a 429 error. Rate-limit-specific retry backoff is therefore not applied.
  2. The detection job silently passes on Claude Code CLI exit code 1 — when all retries are exhausted and Claude Code exits with code 1, the Parse and conclude threat detection step maps the outcome to conclusion: warning rather than failure, making the whole job conclude success. This is a security gap: if the threat detection agent fails entirely, the workflow should be blocked, not silently approved.

Reproduction

The following sequence was observed in a detection job run:

Step: Execute Claude Code CLI

Claude Code CLI made a few tool calls, then hit a rate limit:

{
  "type": "result",
  "subtype": "success",
  "is_error": true,
  "api_error_status": 429,
  "result": "API Error: Request rejected (429) · This request would exceed your account's rate limit. Please try again later.",
  "stop_reason": "stop_sequence"
}

The harness retried 4 times, but classified the error as not a rate limit:

[claude-harness] attempt 1 failed: exitCode=1 isOverloadedError=false isRateLimitError=false isMaxTurnsExit=false hasOutput=true retriesRemaining=3
[claude-harness] attempt 2 failed: exitCode=1 isOverloadedError=false isRateLimitError=false isMaxTurnsExit=false hasOutput=true retriesRemaining=1
[claude-harness] all 3 retries exhausted — giving up (exitCode=1)
##[error]Process completed with exit code 1.

Step: Parse and conclude threat detection

Despite the CLI exiting with code 1 and producing no usable output, the parse step emitted a warning (not failure):

##[error]❌ Failed to parse detection result: No THREAT_DETECTION_RESULT found in detection log. The detection model may have failed to follow the output format.
##[warning]⚠️ ERR_PARSE: ❌ No THREAT_DETECTION_RESULT found in detection log.

The step and job both concluded success.

Root Cause Analysis

Bug 1 — 429 misclassified: The Claude Code CLI wraps the 429 inside its result JSON (is_error: true, api_error_status: 429, stop_reason: stop_sequence) rather than propagating it as a transport-level HTTP error. The harness's isRateLimitError detection appears to check for a different signal (e.g. a transport-level retry header or a specific exit code), so it misses the 429 embedded in the JSON body. The result: no rate-limit backoff, immediate exhaustion of retries.

Bug 2 — Silent pass on detection failure: When ERR_PARSE occurs (no THREAT_DETECTION_RESULT in the log), the harness sets conclusion: warning instead of conclusion: failure. This makes the detection job green even when the agent ran zero useful turns. The safe_outputs job then proceeds as if detection succeeded — a meaningful security gap.

Expected Behavior

  1. When api_error_status: 429 is present in the Claude Code result JSON, isRateLimitError should be true, and rate-limit retry backoff should be applied.
  2. When Claude Code exits with code 1 and produces no THREAT_DETECTION_RESULT, the detection job should fail (not warn), blocking downstream jobs including safe_outputs.

Environment

  • Claude Code CLI version: current (as installed by gh-aw harness)
  • Model: claude-sonnet-4-6

Reported by Claude (claude-sonnet-4-6) based on analysis of detection job logs.

Metadata

Metadata

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions