{"record":{"id":"b9039648f816ce47","repo":"microsoft/semantic-kernel","slug":"expected-an-asyncstream-chatcompletionchunk-respo","errorCode":null,"errorMessage":"Expected an AsyncStream[ChatCompletionChunk] response.","messagePattern":"Expected an AsyncStream\\[ChatCompletionChunk\\] response\\.","errorType":"exception","errorClass":"ServiceInvalidResponseError","httpStatus":null,"severity":"error","filePath":"python/semantic_kernel/connectors/ai/open_ai/services/open_ai_chat_completion_base.py","lineNumber":112,"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, OpenAIChatPromptExecutionSettings):\n            settings = self.get_prompt_execution_settings_from_settings(settings)\n        assert isinstance(settings, OpenAIChatPromptExecutionSettings)  # nosec\n\n        settings.stream = True\n        settings.stream_options = {\"include_usage\": True}\n        settings.messages = self._prepare_chat_history_for_request(chat_history)\n        settings.ai_model_id = settings.ai_model_id or self.ai_model_id\n\n        response = await self._send_request(settings)\n        if not isinstance(response, AsyncStream):\n            raise ServiceInvalidResponseError(\"Expected an AsyncStream[ChatCompletionChunk] response.\")\n        async for chunk in response:\n            if len(chunk.choices) == 0 and chunk.usage is None:\n                continue\n\n            assert isinstance(chunk, ChatCompletionChunk)  # nosec\n            chunk_metadata = self._get_metadata_from_streaming_chat_response(chunk)\n            if (not chunk.choices or len(chunk.choices) == 0) and chunk.usage is not None:\n                # Usage is contained in the last chunk where the choices are empty\n                # We are duplicating the usage metadata to all the choices in the response\n                yield [\n                    StreamingChatMessageContent(\n                        role=AuthorRole.ASSISTANT,\n                        content=\"\",\n                        choice_index=i,\n                        inner_content=chunk,\n                        ai_model_id=settings.ai_model_id,\n                        metadata=chunk_metadata,\n                        function_invoke_attempt=function_invoke_attempt,","sourceCodeStart":94,"sourceCodeEnd":130,"githubUrl":"https://github.com/microsoft/semantic-kernel/blob/c028a0c7dc4f0814cdcbaba9d998f187a41197bf/python/semantic_kernel/connectors/ai/open_ai/services/open_ai_chat_completion_base.py#L94-L130","documentation":"Raised inside the streaming chat-completion generator (_complete_chat_stream) after the OpenAI client returns a response object that is not an openai.AsyncStream. The method unconditionally sets stream=True on the settings and expects the SDK to yield ChatCompletionChunk objects; a non-stream response indicates the request was misconfigured or the SDK version is incompatible.","triggerScenarios":"Calling the streaming completion path (get_streaming_chat_message_content or _complete_chat_stream) when the underlying OpenAI SDK client returns a non-streamed ChatCompletion object — e.g., because stream was overridden elsewhere, a custom client wrapper stripped streaming, or the openai package version returns a different response type.","commonSituations":"Using a mocked or custom AsyncOpenAI client in tests that returns a ChatCompletion instead of an AsyncStream; upgrading/downgrading the openai Python package to a version with a changed streaming contract; a proxy or gateway that buffers and de-chunks the response.","solutions":["Ensure settings.stream is not being overridden to False before or after the streaming call path is entered","Verify the openai package version matches the one required by your semantic-kernel version (check pyproject.toml or requirements.txt)","If using a custom client, confirm it returns an AsyncStream[ChatCompletionChunk] when stream=True is passed","Avoid injecting a pre-configured client that wraps or intercepts the create() call in a way that changes the return type"],"exampleFix":"# before — mock returns a non-stream object\nmock_client.chat.completions.create.return_value = ChatCompletion(...)\n# after — mock returns an AsyncStream\nasync def _fake_stream():\n    yield ChatCompletionChunk(...)\nmock_client.chat.completions.create.return_value = _fake_stream()","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"from openai import AsyncStream\nfrom openai.types.chat import ChatCompletionChunk\n\ndef is_valid_stream_response(response) -> bool:\n    return isinstance(response, AsyncStream)","tryCatchPattern":"from semantic_kernel.exceptions.service_exceptions import ServiceInvalidResponseError\n\ntry:\n    async for chunk in service._complete_chat_stream(...):\n        ...\nexcept ServiceInvalidResponseError as e:\n    logger.error('Streaming response was not an AsyncStream; falling back to non-streaming')\n    response = await service.get_chat_message_content(...)","preventionTips":["Pin the openai SDK version to the one tested by your semantic-kernel release","In tests, always mock streaming endpoints with real AsyncStream-compatible objects"],"tags":["openai","streaming","chat-completion","type-mismatch"],"backgroundTag":null,"analyzedSha":"c028a0c7dc4f0814cdcbaba9d998f187a41197bf","analyzedAt":"2026-08-13T13:48:05.040Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}