{"record":{"id":"ce5086c39a07307d","repo":"microsoft/semantic-kernel","slug":"expected-an-asyncgenerator-response","errorCode":null,"errorMessage":"Expected an AsyncGenerator response.","messagePattern":"Expected an AsyncGenerator response\\.","errorType":"exception","errorClass":"ServiceInvalidResponseError","httpStatus":null,"severity":"error","filePath":"python/semantic_kernel/connectors/ai/anthropic/services/anthropic_chat_completion.py","lineNumber":188,"sourceCode":"    @trace_streaming_chat_completion(MODEL_PROVIDER_NAME)\n    async def _inner_get_streaming_chat_message_contents(\n        self,\n        chat_history: \"ChatHistory\",\n        settings: \"PromptExecutionSettings\",\n        function_invoke_attempt: int = 0,\n    ) -> AsyncGenerator[list[\"StreamingChatMessageContent\"], Any]:\n        if not isinstance(settings, AnthropicChatPromptExecutionSettings):\n            settings = self.get_prompt_execution_settings_from_settings(settings)\n        assert isinstance(settings, AnthropicChatPromptExecutionSettings)  # nosec\n\n        settings.messages, parsed_system_message = self._prepare_chat_history_for_request(chat_history, stream=True)\n        settings.ai_model_id = settings.ai_model_id or self.ai_model_id\n        if settings.system is None and parsed_system_message is not None:\n            settings.system = parsed_system_message\n\n        response = self._send_chat_stream_request(settings, function_invoke_attempt)\n        if not isinstance(response, AsyncGenerator):\n            raise ServiceInvalidResponseError(\"Expected an AsyncGenerator response.\")\n\n        async for message in response:\n            yield message\n\n    @override\n    def _prepare_chat_history_for_request(\n        self,\n        chat_history: \"ChatHistory\",\n        role_key: str = \"role\",\n        content_key: str = \"content\",\n        stream: bool = False,\n    ) -> tuple[list[dict[str, Any]], str | None]:\n        \"\"\"Prepare the chat history for an Anthropic request.\n\n        Allowing customization of the key names for role/author, and optionally overriding the role.\n\n        Args:\n            chat_history: The chat history to prepare.","sourceCodeStart":170,"sourceCodeEnd":206,"githubUrl":"https://github.com/microsoft/semantic-kernel/blob/c028a0c7dc4f0814cdcbaba9d998f187a41197bf/python/semantic_kernel/connectors/ai/anthropic/services/anthropic_chat_completion.py#L170-L206","documentation":"In the streaming path, _inner_get_streaming_chat_message_contents calls _send_chat_stream_request and asserts the result is an AsyncGenerator before iterating. If it is not, ServiceInvalidResponseError is raised. _send_chat_stream_request is itself an async generator (it uses `yield`), so in normal operation this invariant always holds; the error indicates a broken override or an abnormal return.","triggerScenarios":"A subclass overrides _send_chat_stream_request to return something that is not an async generator (e.g. a plain coroutine or list); an early code path returns a non-generator; an anthropic SDK/version mismatch alters the streaming contract.","commonSituations":"Custom subclass of AnthropicChatCompletion that breaks the streaming method's generator contract; using an incompatible anthropic SDK version; monkeypatching that replaces the method.","solutions":["If subclassing, keep _send_chat_stream_request as an async generator (it must use `yield`).","Pin/upgrade the anthropic SDK to a version compatible with this Semantic Kernel release.","Do not monkeypatch or replace the streaming method; if you must, preserve the AsyncGenerator return type.","Use the standard streaming API (get_streaming_chat_message_content) rather than calling internals."],"exampleFix":"// before (broken subclass override)\nasync def _send_chat_stream_request(self, settings, attempt=0):\n    return await self.async_client.messages.stream(**settings.prepare_settings_dict())  # not a generator\n\n// after\nasync def _send_chat_stream_request(self, settings, attempt=0):\n    async with self.async_client.messages.stream(**settings.prepare_settings_dict()) as stream:\n        async for event in stream:\n            yield [self._create_streaming_chat_message_content(event, {}, attempt)]","handlingStrategy":"type-guard","validationCode":"from collections.abc import AsyncGenerator\nimport inspect\nfn = service._send_chat_stream_request\nassert inspect.isasyncgenfunction(fn), '_send_chat_stream_request must be an async generator'","typeGuard":"def streaming_method_is_async_generator(service) -> bool:\n    return inspect.isasyncgenfunction(service._send_chat_stream_request)","tryCatchPattern":"from semantic_kernel.exceptions.service_exceptions import ServiceInvalidResponseError\ntry:\n    async for chunk in service._inner_get_streaming_chat_message_contents(history, settings):\n        ...\nexcept ServiceInvalidResponseError:\n    # fall back to non-streaming completion\n    result = await service._inner_get_chat_message_contents(history, settings)","preventionTips":["Keep _send_chat_stream_request an async generator if subclassing","Pin a compatible anthropic SDK version","Do not monkeypatch the streaming method","Prefer the public streaming API over internals"],"tags":["anthropic","streaming","internal","invariant"],"backgroundTag":null,"analyzedSha":"c028a0c7dc4f0814cdcbaba9d998f187a41197bf","analyzedAt":"2026-08-13T13:48:05.040Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}