Skip to content

Beta AsyncMessages.stream incorrectly in WRAPPED_AMETHODS (breaks async with) #3701

@asia-moonlakeai

Description

@asia-moonlakeai

Bug Description

In opentelemetry-instrumentation-anthropic v0.52.4, the beta AsyncMessages.stream entries are placed in WRAPPED_AMETHODS (async wrapper) instead of WRAPPED_METHODS (sync wrapper). This breaks all uses of async with client.beta.messages.stream(...).

Root Cause

AsyncMessages.stream() is a regular def (not async def) that returns an async context manager (BetaAsyncMessageStreamManager). The async wrapper (_awrap) does response = await wrapped(*args, **kwargs), which wraps the return value in a coroutine. Callers using async with get:

TypeError: 'coroutine' object does not support the asynchronous context manager protocol

The non-beta AsyncMessages.stream is already correctly placed in WRAPPED_METHODS with this comment in the source:

# This method is on an async resource, but is meant to be called as
# an async context manager (async with), which we don't need to await;
# thus, we wrap it with a sync wrapper

The same logic should apply to the beta versions.

Affected Entries

These entries in WRAPPED_AMETHODS should be moved to WRAPPED_METHODS:

# In WRAPPED_AMETHODS (WRONG):
{"package": "anthropic.resources.beta.messages.messages", "object": "AsyncMessages", "method": "stream", ...}
{"package": "anthropic.lib.bedrock._beta_messages", "object": "AsyncMessages", "method": "stream", ...}

Fix

Move the two beta AsyncMessages.stream entries from WRAPPED_AMETHODS to WRAPPED_METHODS, matching how the non-beta AsyncMessages.stream is already handled. The sync wrapper correctly handles async context managers via the is_stream_manager() check.

Reproduction

import anthropic

client = anthropic.AsyncAnthropic()

# After AnthropicInstrumentor().instrument():
async with client.beta.messages.stream(
    model="claude-sonnet-4-20250514",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Hello"}],
    betas=["interleaved-thinking-2025-05-14"],
    thinking={"type": "enabled", "budget_tokens": 1024},
) as stream:
    async for event in stream:
        ...
# TypeError: 'coroutine' object does not support the asynchronous context manager protocol

Version

opentelemetry-instrumentation-anthropic==0.52.4

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions