Skip to content

fix(cli): include http response body in target errors#207

Merged
jithin23-kv merged 2 commits into
KeyValueSoftwareSystems:masterfrom
Karthik-EM:fix/capture-http-errors
Jul 21, 2026
Merged

fix(cli): include http response body in target errors#207
jithin23-kv merged 2 commits into
KeyValueSoftwareSystems:masterfrom
Karthik-EM:fix/capture-http-errors

Conversation

@Karthik-EM

@Karthik-EM Karthik-EM commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Problem

When the target agent returned an HTTP error with a response body, the CLI only displayed the status code (for example, HTTP 400), making it difficult to identify the actual error.

Solution

Capture the HTTP response body and include it in the TargetStopError message so the CLI displays both the status code and the server's error response.

Changes

  • Updated core/src/targets/agentTarget.ts to include the HTTP response body in error messages.

Closes

Closes #176

How to test

  1. Configure a target to return a 400 or 500 response with a JSON error body.
  2. Run an Opfor attack against the target.
  3. Verify that the CLI displays both the HTTP status code and the response body.

Screenshots

N/A

Summary by CodeRabbit

  • Bug Fixes
    • Improved HTTP error messages with response details, truncated to 500 characters.
    • Retryable HTTP failures now provide more useful error context while preserving existing retry and backoff behavior.
    • Non-retryable failures clearly indicate whether the response body was unavailable.

@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 975c5b61-b218-41c4-8854-d44794f77efd

📥 Commits

Reviewing files that changed from the base of the PR and between cfb39fd and 20221e1.

📒 Files selected for processing (1)
  • core/src/targets/agentTarget.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • core/src/targets/agentTarget.ts

Walkthrough

Changes

Agent HTTP error reporting

Layer / File(s) Summary
Detailed HTTP error handling
core/src/targets/agentTarget.ts
Both failed HTTP response paths read up to 500 characters of response text, include it in retryable errors, and use the same message for non-retryable TargetStopError failures while preserving retry and rate-limit behavior.

Estimated code review effort: 2 (Simple) | ~10 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately summarizes the main change: including HTTP response bodies in target errors.
Description check ✅ Passed The description covers the problem, solution, changes, testing, and issue reference well enough for this repository.
Linked Issues check ✅ Passed The change satisfies #176 by surfacing agent HTTP response bodies in error messages instead of only the status code.
Out of Scope Changes check ✅ Passed The PR stays focused on agentTarget HTTP error messaging and does not introduce unrelated changes.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
core/src/targets/agentTarget.ts (1)

236-246: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Extract duplicate HTTP error handling into a helper function.

The error handling logic for non-OK responses is identical across both request paths. Consider extracting it into a helper function to keep the code DRY.

  • core/src/targets/agentTarget.ts#L236-L246: Replace with a call to the new helper function.
  • core/src/targets/agentTarget.ts#L267-L278: Replace with a call to the new helper function.
♻️ Proposed refactor

Define a helper function outside of callHttp:

async function handleHttpError(response: Response): Promise<string> {
  const errorBody = await response.text().catch(() => "");
  const message = errorBody
    ? `Target returned HTTP ${response.status}: ${errorBody}`
    : `Target returned HTTP ${response.status}`;

  if (!isRetryableStatus(response.status)) {
    throw new TargetStopError(message);
  }
  return `ERROR: ${message}`;
}

Then, replace the duplicated blocks with calls to this helper:

-        const errorBody = await res.text().catch(() => "");
-
-        const message = errorBody
-          ? `Target returned HTTP ${res.status}: ${errorBody}`
-          : `Target returned HTTP ${res.status}`;
-        // Non-retryable status (4xx except 429) - stop the run
-        if (!isRetryableStatus(res.status)) {
-          throw new TargetStopError(message);
-        }
-        // Retryable (5xx) - return error but continue
-        return `ERROR: ${message}`;
+        return await handleHttpError(res);
-      const errorBody = await res2.text().catch(() => "");
-
-      const message = errorBody
-        ? `Target returned HTTP ${res2.status}: ${errorBody}`
-        : `Target returned HTTP ${res2.status}`;
-
-      // Non-retryable status (4xx except 429) - stop the run
-      if (!isRetryableStatus(res2.status)) {
-        throw new TargetStopError(message);
-      }
-      // Retryable (5xx) - return error but continue
-      return `ERROR: ${message}`;
+      return await handleHttpError(res2);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@core/src/targets/agentTarget.ts` around lines 236 - 246, Extract the
duplicated non-OK response handling from callHttp into a shared handleHttpError
helper that reads the response body, builds the status message, throws
TargetStopError for non-retryable statuses, and returns the retryable error
string otherwise. Replace the handling blocks at core/src/targets/agentTarget.ts
lines 236-246 and 267-278 with calls to this helper.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@core/src/targets/agentTarget.ts`:
- Around line 236-246: Extract the duplicated non-OK response handling from
callHttp into a shared handleHttpError helper that reads the response body,
builds the status message, throws TargetStopError for non-retryable statuses,
and returns the retryable error string otherwise. Replace the handling blocks at
core/src/targets/agentTarget.ts lines 236-246 and 267-278 with calls to this
helper.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 3a21eba5-b18b-4f6b-b5cc-761a93934c0f

📥 Commits

Reviewing files that changed from the base of the PR and between fbc8592 and 4023e85.

📒 Files selected for processing (3)
  • core/src/targets/agentTarget.ts
  • skills/agent-redteaming/opfor-setup/catalog.json
  • skills/mcp-redteaming/opfor-setup/catalog.json

@Karthik-EM
Karthik-EM force-pushed the fix/capture-http-errors branch from 4023e85 to b4ebc7c Compare July 20, 2026 08:02
@Karthik-EM
Karthik-EM force-pushed the fix/capture-http-errors branch from b4ebc7c to cfb39fd Compare July 20, 2026 08:19

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
core/src/targets/agentTarget.ts (1)

236-246: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Truncate the error response to prevent log flooding.

Both code paths read the complete error response body into the error message without bounding its length. If the target endpoint is behind a proxy or WAF that returns a large HTML error page (e.g., for 502 or 504 errors), the resulting string can be excessively large and will flood the CLI output and application logs. Creating a helper function to truncate the response mitigates this risk and removes duplicate logic.

  • core/src/targets/agentTarget.ts#L236-L246: Replace this block with a call to a shared helper that truncates the text and handles the error flow.
  • core/src/targets/agentTarget.ts#L267-L278: Replace this block with the same helper call.
♻️ Proposed refactor

Add this helper outside the try block (e.g., around line 208):

  const handleHttpError = async (response: Response): Promise<string> => {
    const rawBody = await response.text().catch(() => "");
    const errorBody = rawBody.length > 1000 ? rawBody.slice(0, 1000) + "... (truncated)" : rawBody;
    const message = errorBody
      ? `Target returned HTTP ${response.status}: ${errorBody}`
      : `Target returned HTTP ${response.status}`;

    if (!isRetryableStatus(response.status)) {
      throw new TargetStopError(message);
    }
    return `ERROR: ${message}`;
  };

Then replace both error-handling branches with a call to the helper:

- core/src/targets/agentTarget.ts#L236-L246:

-        const errorBody = await res.text().catch(() => "");
-
-        const message = errorBody
-          ? `Target returned HTTP ${res.status}: ${errorBody}`
-          : `Target returned HTTP ${res.status}`;
-        // Non-retryable status (4xx except 429) - stop the run
-        if (!isRetryableStatus(res.status)) {
-          throw new TargetStopError(message);
-        }
-        // Retryable (5xx) - return error but continue
-        return `ERROR: ${message}`;
+        return await handleHttpError(res);

- core/src/targets/agentTarget.ts#L267-L278:

-      const errorBody = await res2.text().catch(() => "");
-
-      const message = errorBody
-        ? `Target returned HTTP ${res2.status}: ${errorBody}`
-        : `Target returned HTTP ${res2.status}`;
-
-      // Non-retryable status (4xx except 429) - stop the run
-      if (!isRetryableStatus(res2.status)) {
-        throw new TargetStopError(message);
-      }
-      // Retryable (5xx) - return error but continue
-      return `ERROR: ${message}`;
+      return await handleHttpError(res2);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@core/src/targets/agentTarget.ts` around lines 236 - 246, Add a shared
handleHttpError helper outside the try block in core/src/targets/agentTarget.ts,
using a maximum 1000-character response body with a truncation suffix,
preserving status messaging and TargetStopError behavior for non-retryable
responses. Replace the duplicated error-handling blocks at
core/src/targets/agentTarget.ts:236-246 and
core/src/targets/agentTarget.ts:267-278 with calls to this helper.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@core/src/targets/agentTarget.ts`:
- Around line 236-246: Add a shared handleHttpError helper outside the try block
in core/src/targets/agentTarget.ts, using a maximum 1000-character response body
with a truncation suffix, preserving status messaging and TargetStopError
behavior for non-retryable responses. Replace the duplicated error-handling
blocks at core/src/targets/agentTarget.ts:236-246 and
core/src/targets/agentTarget.ts:267-278 with calls to this helper.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: febb8f0c-c64e-44e4-8919-2adad4e021a8

📥 Commits

Reviewing files that changed from the base of the PR and between b4ebc7c and cfb39fd.

📒 Files selected for processing (3)
  • core/src/targets/agentTarget.ts
  • skills/agent-redteaming/opfor-setup/catalog.json
  • skills/mcp-redteaming/opfor-setup/catalog.json
🚧 Files skipped from review as they are similar to previous changes (2)
  • skills/mcp-redteaming/opfor-setup/catalog.json
  • skills/agent-redteaming/opfor-setup/catalog.json

@jithin23-kv
jithin23-kv force-pushed the fix/capture-http-errors branch from 0d7a781 to 20221e1 Compare July 21, 2026 05:59
@jithin23-kv

jithin23-kv commented Jul 21, 2026

Copy link
Copy Markdown
Collaborator

LGTM

A couple of small things I pushed to the branch:

  • Reverted the catalog.json changes. The only diff there was the _source paths flipping from / to \\ (Windows-style backslashes) — looks like the catalogs got regenerated on Windows. Nothing reads the _source field (it's just build-time provenance), so it's harmless either way, but the backslash form is non-portable and would actually fail the build:catalog:check CI job on the Linux runner. Reverted to keep the PR focused on the real change.
  • Capped the error body at 500 chars. The captured body now flows into the error message and gets persisted into the run report, so an unbounded 5xx (big HTML page / stack trace) could bloat things. Added a .slice(0, 500), matching what we already do in openaiCompatible.ts / httpClient.ts.

Thank you for your contribution!

@jithin23-kv
jithin23-kv merged commit c8c9f72 into KeyValueSoftwareSystems:master Jul 21, 2026
8 checks passed
@Karthik-EM
Karthik-EM deleted the fix/capture-http-errors branch July 21, 2026 06:15
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.

feat: Show the response of agent errors instead of just an HTTP status code.

2 participants