Skip to content

fix(executor): handle error subtypes in ResultMessage to prevent task… - #476

Merged
qdaxb merged 1 commit into
mainfrom
fix/handle-error-subtypes-in-result-message
Feb 6, 2026
Merged

qdaxb merged 1 commit into
mainfrom
fix/handle-error-subtypes-in-result-message

Conversation

@FicoHu

@FicoHu FicoHu commented Feb 6, 2026 •

Copy link
Copy Markdown
Contributor

… stuck

When Claude SDK returns ResultMessage with subtype like "error_during_execution" but is_error=False, the task would remain in RUNNING state indefinitely.

This fix handles all error_ prefixed subtypes per official documentation:

  • error_during_execution: Error occurred during execution
  • error_max_turns: Reached turn limit
  • error_max_budget_usd: Exceeded budget limit
  • error_max_structured_output_retries: Reached structured output retry limit

Ref: https://platform.claude.com/docs/agent-sdk/stop-reasons

Summary by CodeRabbit

  • Bug Fixes
    • Improved error handling to properly detect and mark certain error conditions as failed, ensuring the system responds appropriately with accurate status updates and progress reporting.

… stuck

When Claude SDK returns ResultMessage with subtype like "error_during_execution"
but is_error=False, the task would remain in RUNNING state indefinitely.

This fix handles all error_ prefixed subtypes per official documentation:
- error_during_execution: Error occurred during execution
- error_max_turns: Reached turn limit
- error_max_budget_usd: Exceeded budget limit
- error_max_structured_output_retries: Reached structured output retry limit

Ref: https://platform.claude.com/docs/agent-sdk/stop-reasons

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Feb 6, 2026 •

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

The PR adds explicit handling for error subtypes in ResultMessage processing within the response processor. When a message subtype starts with "error_", it logs the subtype, adds a thinking step, updates the workbench status to failed, reports progress failure, and returns TaskStatus.FAILED, ensuring error conditions are treated as hard failures.

Changes

Cohort / File(s) Summary
Error Subtype Handling
executor/agents/claude_code/response_processor.py
Adds ~32 lines to handle error subtypes in ResultMessage processing, triggering failure status updates, progress reporting with 100% failure, and early termination when msg.subtype starts with "error_".

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

  • feat: init public resources #180: Restructures ResultMessage processing in the same file to async _process_result_message with retry logic, making both PRs relevant to error handling flow.

Suggested reviewers

  • qdaxb

Poem

🐰 When subtypes whisper "error" with a sigh,
We log their names and let them swiftly die,
Status turns to failed, progress falls to zero,
A fail-fast dance—our code becomes a hero! ✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix(executor): handle error subtypes in ResultMessage to prevent task…' accurately describes the main change in the pull request.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/handle-error-subtypes-in-result-message

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 and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@executor/agents/claude_code/response_processor.py`:
- Around line 746-776: Guard uses of state_manager in the error-subtype handling
branch (the block that checks if msg.subtype and
msg.subtype.startswith("error_") and returns TaskStatus.FAILED) by checking if
state_manager is not None before calling state_manager.update_workbench_status
and state_manager.report_progress; if state_manager is None skip those calls
(but still log and add the thinking step via thinking_manager as currently
done). Apply the same None-guard pattern to the earlier is_error handling branch
(the block that handles msg.is_error) to prevent AttributeError when
state_manager is None. Ensure you reference the same symbols: msg.subtype,
thinking_manager.add_thinking_step, state_manager.update_workbench_status,
state_manager.report_progress, and TaskStatus.FAILED.
🧹 Nitpick comments (1)
executor/agents/claude_code/response_processor.py (1)

752-776: Consider extracting the shared failure-reporting logic to reduce duplication.

Lines 760–776 are nearly identical to lines 726–744 (the is_error failure path): add thinking step → update workbench to "failed" → report progress at 100% FAILED → return TaskStatus.FAILED. Extracting a small helper (e.g., _report_failure(state_manager, thinking_manager, masked_details, message)) would eliminate this duplication and make future changes (like the None guard above) a single-point fix.

Comment on lines +746 to +776
# Handle error subtypes (is_error=False but execution ended with error condition)
# Official subtypes per https://platform.claude.com/docs/agent-sdk/stop-reasons:
# - error_during_execution: Error occurred during execution
# - error_max_turns: Reached turn limit
# - error_max_budget_usd: Exceeded budget limit
# - error_max_structured_output_retries: Reached structured output retry limit
if msg.subtype and msg.subtype.startswith("error_"):
result_str = (
str(msg.result) if msg.result is not None else f"Task ended: {msg.subtype}"
)
logger.error(
f"Task ended with subtype={msg.subtype} (is_error={msg.is_error}): {result_str}"
)

# Add thinking step for error result
if thinking_manager:
thinking_manager.add_thinking_step(
title="thinking.task_execution_failed",
report_immediately=False,
use_i18n_keys=True,
details=masked_result_details,
)

# Update workbench status to failed
state_manager.update_workbench_status("failed")

# Report error using state manager
state_manager.report_progress(
progress=100, status=TaskStatus.FAILED.value, message=result_str
)
return TaskStatus.FAILED

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Logic is correct and well-documented; guard state_manager against None for robustness.

The placement and condition (msg.subtype.startswith("error_") after the is_error gate) correctly catch the described scenario where is_error=False but the subtype signals an error. The startswith approach is nicely forward-compatible with future error subtypes.

However, state_manager is used at lines 770 and 773 without a None check. The outer exception handler (line 181) and other places in process_response (line 91) do guard against None. While this mirrors the existing is_error block (line 736), both paths can raise AttributeError if state_manager is None.

Proposed fix
         # Update workbench status to failed
-        state_manager.update_workbench_status("failed")
+        if state_manager:
+            state_manager.update_workbench_status("failed")

         # Report error using state manager
-        state_manager.report_progress(
-            progress=100, status=TaskStatus.FAILED.value, message=result_str
-        )
+            state_manager.report_progress(
+                progress=100, status=TaskStatus.FAILED.value, message=result_str
+            )
         return TaskStatus.FAILED

The same fix should be applied to the pre-existing is_error block at lines 736–741.

🤖 Prompt for AI Agents
In `@executor/agents/claude_code/response_processor.py` around lines 746 - 776,
Guard uses of state_manager in the error-subtype handling branch (the block that
checks if msg.subtype and msg.subtype.startswith("error_") and returns
TaskStatus.FAILED) by checking if state_manager is not None before calling
state_manager.update_workbench_status and state_manager.report_progress; if
state_manager is None skip those calls (but still log and add the thinking step
via thinking_manager as currently done). Apply the same None-guard pattern to
the earlier is_error handling branch (the block that handles msg.is_error) to
prevent AttributeError when state_manager is None. Ensure you reference the same
symbols: msg.subtype, thinking_manager.add_thinking_step,
state_manager.update_workbench_status, state_manager.report_progress, and
TaskStatus.FAILED.

@qdaxb
qdaxb merged commit adb252c into main Feb 6, 2026
13 checks passed
@qdaxb
qdaxb deleted the fix/handle-error-subtypes-in-result-message branch February 6, 2026 08:29
maquan0927 pushed a commit to maquan0927/Wegent that referenced this pull request Feb 11, 2026
… stuck (wecode-ai#476)

When Claude SDK returns ResultMessage with subtype like "error_during_execution"
but is_error=False, the task would remain in RUNNING state indefinitely.

This fix handles all error_ prefixed subtypes per official documentation:
- error_during_execution: Error occurred during execution
- error_max_turns: Reached turn limit
- error_max_budget_usd: Exceeded budget limit
- error_max_structured_output_retries: Reached structured output retry limit

Ref: https://platform.claude.com/docs/agent-sdk/stop-reasons

Co-authored-by: yunpeng7 <yunpeng7@staff.weibo.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
fengkuizhi pushed a commit that referenced this pull request Mar 3, 2026
feat: Add OpenAPI v1/responses endpoint and API Key management (#476)

See merge request weibo_rd/common/wecode/wegent!766
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