Skip to content

Conversation

@maxisbey
Copy link
Contributor

@maxisbey maxisbey commented Dec 3, 2025

Fixes an intermittent UnboundLocalError that could occur in send_request() at the line checking isinstance(response_or_error, JSONRPCError).

Motivation and Context

We received a report of intermittent UnboundLocalError exceptions in send_request():

UnboundLocalError: cannot access local variable 'response_or_error' where it is not associated with a value

This can occur due to a race condition in anyio's fail_after context manager (anyio#589) where exceptions may be incorrectly suppressed, leaving the response_or_error variable unassigned while execution continues past the try/except block.

The fix:

  • Initializes response_or_error to None before the try block
  • Adds a _process_response static method with a defensive None check
  • Handles EndOfStream and ClosedResourceError exceptions explicitly
  • Uses try/except/else structure for cleaner control flow

How Has This Been Tested?

  • Added unit tests for _process_response covering all code paths
  • All existing session tests pass (23/23)
  • Created a minimal reproduction script demonstrating the bug and fix

Breaking Changes

None. This is a defensive fix that handles edge cases more gracefully.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

Additional context

Closes #1717

The root cause is a race condition in anyio where fail_after's cancel scope can incorrectly suppress exceptions when a timeout and successful completion happen simultaneously. While this was reportedly fixed in anyio 4.0 (PR #591), edge cases may remain. This fix adds defensive code to handle the scenario gracefully rather than crashing with UnboundLocalError.

@maxisbey maxisbey added the bug Something isn't working label Dec 3, 2025
Fixes an intermittent UnboundLocalError that could occur in send_request()
when anyio's fail_after context manager incorrectly suppresses exceptions
due to a race condition (anyio#589).

Changes:
- Initialize response_or_error to None before the try block
- Add _process_response static method with defensive None check
- Handle EndOfStream and ClosedResourceError exceptions explicitly
- Use try/except/else structure for cleaner control flow
- Add unit tests for _process_response

Closes #1717
@maxisbey maxisbey force-pushed the fix/send-request-unbound-local-error branch from bf42fa1 to ee2a010 Compare December 3, 2025 15:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

UnboundLocalError in send_request when response_or_error is not assigned

2 participants