Skip to content

fix(server): recover panics in executeRegularToolAsTask (hybrid task mode) - #939

Open
manjunathbhaskar wants to merge 1 commit into
mark3labs:mainfrom
manjunathbhaskar:fix/executeRegularToolAsTask-panic-recovery
Open

fix(server): recover panics in executeRegularToolAsTask (hybrid task mode)#939
manjunathbhaskar wants to merge 1 commit into
mark3labs:mainfrom
manjunathbhaskar:fix/executeRegularToolAsTask-panic-recovery

Conversation

@manjunathbhaskar

@manjunathbhaskar manjunathbhaskar commented Jul 23, 2026

Copy link
Copy Markdown

Summary

Adds panic recovery to executeRegularToolAsTask, the goroutine used when a regular tool with TaskSupportOptional is invoked asynchronously (called with task params) in hybrid mode.

Problem

#880 added panic recovery to executeTaskTool after a report that an unrecovered panic in that goroutine would crash the whole server. That fix didn't cover the sibling function, executeRegularToolAsTask, which still runs without a recover guard.

Reproduced directly: a panicking handler run through this path propagates the panic uncaught out of the goroutine, which in Go terminates the entire process -- not just the failing request. Any tool registered with TaskSupportOptional that panics when called asynchronously currently takes down the server for every connected client.

Fix

Mirrors #880's exact pattern -- a defer/recover() that completes the task as Failed with the panic message via completeTask, instead of letting the panic escape.

Testing

  • Added TestExecuteRegularToolAsTask_PanicRecovery, mirroring fix: add panic recovery to task goroutines, fix cleanup goroutine leak #880's own TestExecuteTaskTool_PanicRecovery.
  • Confirmed the test crashes the process on main (unrecovered panic) and passes cleanly with this change.
  • Full suite (go build, go vet, go test ./..., go test -race ./server/...): all green, zero regressions.

Note on related open PRs

#900 and #889 both address a different bug in this same function (context cancellation cascading from the HTTP request lifecycle, #897) via different mechanisms. Neither touches panic recovery, and neither conflicts with this change at the line level -- this PR only adds a defer block at the top of the function body.

Summary by CodeRabbit

  • Bug Fixes
    • Improved reliability when asynchronous tool execution encounters a panic.
    • Failed tasks now receive a completed status with a clear error message, including the original failure details.
    • Added coverage to verify panic recovery and accurate task status reporting.

@mark-iii-labs-huly

Copy link
Copy Markdown

Connected to Huly®: MCP_G-503

@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

Adds panic recovery to asynchronous regular tool task execution so panicking handlers complete their tasks with failed status, plus a test that verifies completion and preserved panic details.

Changes

Regular tool task recovery

Layer / File(s) Summary
Panic recovery and validation
server/server.go, server/regular_tool_as_task_panic_test.go
executeRegularToolAsTask recovers handler panics and completes the task with an error; the test verifies failed status and recovery messages, including the original panic text.

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

Possibly related PRs

Suggested reviewers: quentinbisson, ezynda3

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description explains the fix, but it does not follow the required template sections like Type of Change and Checklist. Add the template sections: Description, Fixes #..., Type of Change, Checklist, and any relevant MCP Spec/Additional Information entries.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly states the fix and target function, matching the main change.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ 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
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

🧹 Nitpick comments (1)
server/regular_tool_as_task_panic_test.go (1)

22-41: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Exercise the real hybrid dispatch path.

This test calls executeRegularToolAsTask directly and leaves Tool.Execution unset, so it bypasses handleTaskAugmentedToolCall and does not prove that a TaskSupportOptional regular tool is routed into this recovery path. Register the tool with optional task support and invoke the production entrypoint.

🤖 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 `@server/regular_tool_as_task_panic_test.go` around lines 22 - 41, Update the
panic test to set the tool’s Execution to TaskSupportOptional, register the tool
with the server, and invoke handleTaskAugmentedToolCall instead of
executeRegularToolAsTask. Preserve the existing task setup and assertions while
exercising the production hybrid dispatch path for the registered regular tool.
🤖 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.

Inline comments:
In `@server/server.go`:
- Around line 2225-2228: Sanitize panic details in the task error contract: in
server/server.go lines 2225-2228, retain detailed panic diagnostics in
server-side logging or recovery handling but pass a generic client-safe error to
completeTask. Update server/regular_tool_as_task_panic_test.go lines 52-54 to
assert the generic sanitized status message instead of raw panic text.

---

Nitpick comments:
In `@server/regular_tool_as_task_panic_test.go`:
- Around line 22-41: Update the panic test to set the tool’s Execution to
TaskSupportOptional, register the tool with the server, and invoke
handleTaskAugmentedToolCall instead of executeRegularToolAsTask. Preserve the
existing task setup and assertions while exercising the production hybrid
dispatch path for the registered regular tool.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: e12abc4e-2222-4300-b54e-da0d73cf092a

📥 Commits

Reviewing files that changed from the base of the PR and between e395444 and bcd5c7c.

📒 Files selected for processing (2)
  • server/regular_tool_as_task_panic_test.go
  • server/server.go

Comment thread server/server.go
Comment on lines +2225 to +2228
defer func() {
if r := recover(); r != nil {
s.completeTask(entry, nil, fmt.Errorf("panic in task tool handler %s: %v", request.Params.Name, r))
}

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.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Sanitize panic details across the task error contract.

Raw panic values can leak sensitive handler or implementation details through task status notifications.

  • server/server.go#L2225-L2228: record detailed panic diagnostics server-side, but complete the task with a generic client-safe error.
  • server/regular_tool_as_task_panic_test.go#L52-L54: assert the sanitized status message rather than the raw panic text.
📍 Affects 2 files
  • server/server.go#L2225-L2228 (this comment)
  • server/regular_tool_as_task_panic_test.go#L52-L54
🤖 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 `@server/server.go` around lines 2225 - 2228, Sanitize panic details in the
task error contract: in server/server.go lines 2225-2228, retain detailed panic
diagnostics in server-side logging or recovery handling but pass a generic
client-safe error to completeTask. Update
server/regular_tool_as_task_panic_test.go lines 52-54 to assert the generic
sanitized status message instead of raw panic text.

@manjunathbhaskar

manjunathbhaskar commented Jul 23, 2026

Copy link
Copy Markdown
Author

Good catch. I intentionally mirrored the exact pattern from #880 (executeTaskTool) -- same fmt.Errorf(...) -> completeTask -> StatusMessage -> sendTaskStatusNotification broadcast -- so both sibling task-execution paths stay consistent with each other.

If sanitizing panic messages across the task contract is preferred, I think that's best handled as a separate follow-up covering both paths together, rather than creating an inconsistency here. Happy to open that if there's interest!

manjunathbhaskar added a commit to manjunathbhaskar/manjunathbhaskar that referenced this pull request Aug 5, 2026
- Promote deepset-ai/haystack#12217 from open to merged
- Add mark3labs/mcp-go#939 to open
- Add 567-labs/instructor#2476 to closed

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.

1 participant