{"record":{"id":"644f4ab0c2edce10","repo":"openai/openai-python","slug":"expected-custom-parse-type-to-be-a-subclass-of-st-644f4a","errorCode":null,"errorMessage":"Expected custom parse type to be a subclass of {Stream} or {AsyncStream}","messagePattern":"Expected custom parse type to be a subclass of (.+?) or (.+?)","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"src/openai/_response.py","lineNumber":145,"sourceCode":"        )\n\n    def _parse(self, *, to: type[_T] | None = None) -> R | _T:\n        cast_to = to if to is not None else self._cast_to\n\n        # unwrap `TypeAlias('Name', T)` -> `T`\n        if is_type_alias_type(cast_to):\n            cast_to = cast_to.__value__  # type: ignore[unreachable]\n\n        # unwrap `Annotated[T, ...]` -> `T`\n        if cast_to and is_annotated_type(cast_to):\n            cast_to = extract_type_arg(cast_to, 0)\n\n        origin = get_origin(cast_to) or cast_to\n\n        if self._is_sse_stream:\n            if to:\n                if not is_stream_class_type(to):\n                    raise TypeError(f\"Expected custom parse type to be a subclass of {Stream} or {AsyncStream}\")\n\n                return cast(\n                    _T,\n                    to(\n                        cast_to=extract_stream_chunk_type(\n                            to,\n                            failure_message=\"Expected custom stream type to be passed with a type argument, e.g. Stream[ChunkType]\",\n                        ),\n                        response=self.http_response,\n                        client=cast(Any, self._client),\n                        options=self._options,\n                    ),\n                )\n\n            if self._stream_cls:\n                return cast(\n                    R,\n                    self._stream_cls(","sourceCodeStart":127,"sourceCodeEnd":163,"githubUrl":"https://github.com/openai/openai-python/blob/9917c6e28e66e90e1227b3d223c06a8c5441515a/src/openai/_response.py#L127-L163","documentation":"When parsing an SSE streaming response with a custom cast_to type, that type must be a subclass of Stream or AsyncStream so the SDK can wrap the SSE iterator. Any other type (a plain model, dict, etc.) can't receive the stream and TypeError is raised.","triggerScenarios":"Calling .with_streaming_response...parse(MyModel) or .parse(some_non_stream_type) on a streaming endpoint; passing a custom class to cast_to that doesn't inherit from Stream/AsyncStream.","commonSituations":"Reusing a non-stream parse type with the streaming client; custom response wrappers that forget to subclass Stream/AsyncStream.","solutions":["Parse streams with the generated chunk type (e.g. stream = client.chat.completions.create(..., stream=True)) and iterate it","If using a custom stream class, make it subclass openai.Stream (sync) or openai.AsyncStream (async)","Use the non-streaming client method if you want a plain model back"],"exampleFix":"// before\nresp = client.chat.completions.with_streaming_response.create(...)\nresult = resp.parse(ChatCompletion)  # not a Stream subclass\n// after\nwith client.chat.completions.with_streaming_response.create(...) as resp:\n    for chunk in resp.parse():  # default Stream[ChatCompletionChunk]\n        ...","handlingStrategy":"type-guard","validationCode":"from openai import Stream, AsyncStream\nassert issubclass(cast_to, (Stream, AsyncStream)) or not is_streaming, 'custom parse type must subclass Stream'","typeGuard":"from openai import Stream, AsyncStream\n\ndef is_stream_class(t: type) -> TypeGuard[type[Stream] | type[AsyncStream]]:\n    return isinstance(t, type) and issubclass(t, (Stream, AsyncStream))","tryCatchPattern":null,"preventionTips":["Use generated chunk types for streaming parse","Subclass Stream/AsyncStream for custom stream wrappers"],"tags":["python","streaming","sse","type-error","response-parsing"],"backgroundTag":"invalid-stream-parse-type","analyzedSha":"9917c6e28e66e90e1227b3d223c06a8c5441515a","analyzedAt":"2026-08-28T11:46:34.183Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}