From 3f319b7d8af75e579b473c3a27756b1122f15d0d Mon Sep 17 00:00:00 2001 From: Johannes du Plessis Date: Fri, 8 May 2026 15:40:05 -0700 Subject: [PATCH] reviewer: surface GitHub error details when publish_review fails (#1282) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit post_pull_request_review used to swallow the HTTPError and return None, so the tool result was just "Failed to POST PR review" with no status or body — the actual cause (e.g. 422 invalid inline comment, 404 app not installed) only lived in logs. Capture status + body and propagate into the tool result so the agent (and traces) can see why. --- agent/reviewer_publish.py | 15 +++++++++++++-- agent/tools/publish_review.py | 5 +++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/agent/reviewer_publish.py b/agent/reviewer_publish.py index f0222a13..f608efb1 100644 --- a/agent/reviewer_publish.py +++ b/agent/reviewer_publish.py @@ -122,9 +122,20 @@ async def post_pull_request_review( try: response = await client.post(url, headers=headers, json=payload, timeout=30) response.raise_for_status() - except httpx.HTTPError: + except httpx.HTTPStatusError as e: + body = (e.response.text or "")[:500] + logger.exception( + "Failed to POST PR review for %s/%s#%s: %s %s", + owner, + repo, + pr_number, + e.response.status_code, + body, + ) + return {"_error": f"HTTP {e.response.status_code}: {body}"} + except httpx.HTTPError as e: logger.exception("Failed to POST PR review for %s/%s#%s", owner, repo, pr_number) - return None + return {"_error": f"{type(e).__name__}: {e}"} data = response.json() return data if isinstance(data, dict) else None diff --git a/agent/tools/publish_review.py b/agent/tools/publish_review.py index 2c3566f3..5f32f00a 100644 --- a/agent/tools/publish_review.py +++ b/agent/tools/publish_review.py @@ -159,6 +159,11 @@ async def _publish_review_async( ) if review_response is None: return {"success": False, "error": "Failed to POST PR review"} + if isinstance(review_response, dict) and "_error" in review_response: + return { + "success": False, + "error": f"Failed to POST PR review: {review_response['_error']}", + } review_id = review_response.get("id") if isinstance(review_response, dict) else None if review_id is not None and inline_comments: