Skip to content

[Bug]: TTS fails to parse 429 warning message #617

@kyu-aurelian

Description

@kyu-aurelian

Summary

when DG returns 429 error message, it fails to parse and completely fails the request

What happened?

it should just call on_warning call back, but it's entirely failing the connection.

Steps to reproduce

n/a

Minimal code sample

n/a

Logs / traceback

I think there is a gap in how DSK handles warning message between the old and new SDK version.
message:

{'type': 'Warning', 'warn_code': 'EXCESSIVE_FLUSH', 'warn_msg': 'Rate limit exceeded for flushes. Please try again later.'}

stack trace from the new SDK:

Traceback (most recent call last):
File "/app/call_handling/consumers/synthesizer/provider/deepgram.py", line 140, in _listen
await connection.start_listening()
File "/app/.venv/lib/python3.11/site-packages/deepgram/speak/v1/socket_client.py", line 84, in start_listening
parsed, is_binary = self._process_message(raw_message)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/app/.venv/lib/python3.11/site-packages/deepgram/s\peak/v1/socket_client.py", line 62, in _process_message
processed = self._handle_json_message(raw_message)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/app/.venv/lib/python3.11/site-packages/deepgram/speak/v1/socket_client.py", line 54, in _handle_json_message
return parse_obj_as(V1SocketClientResponse, json_data) # type: ignore
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/app/.venv/lib/python3.11/site-packages/deepgram/core/pydantic_utilities.py", line 43, in parse_obj_as
return adapter.validate_python(dealiased_object)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/app/.venv/lib/python3.11/site-packages/pydantic/type_adapter.py", line 421, in validate_python
return self.validator.validate_python(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
pydantic_core._pydantic_core.ValidationError: 10 validation errors for union[bytes,SpeakV1MetadataEvent,SpeakV1ControlEvent,SpeakV1WarningEvent]
bytes
Input should be a valid bytes [type=bytes_type, input_value={'type': 'Warning', 'warn...lease try again later.'}, input_type=dict]
async def start_listening(self):
  ...
  try:
    async for raw_message in self._websocket:
      parsed, is_binary = self._process_message(raw_message)
  ...

def _handle_json_message(self, message: str) -> typing.Any:
  """Handle a JSON message by parsing it."""
  json_data = json.loads(message)
  return parse_obj_as(V1SocketClientResponse, json_data)  # type: ignore

In the new SDK, it just tries to parse it into V1SocketClientResponse (SpeakV1WarningEvent specifically), but there is mismatch between property names, and it fails:

class SpeakV1WarningEvent(UniversalBaseModel):
    """
    Warning event from the TTS WebSocket
    """
    
    type: typing.Literal["Warning"]
    """Message type identifier"""
    
    description: str
    """A description of what went wrong"""
    
    code: str
    """Error code identifying the type of error"""
SpeakV1WarningEvent.description
Field required [type=missing, input_value={'type': 'Warning', 'warn...lease try again later.'}, input_type=dict]
For further information visit https://errors.pydantic.dev/2.11/v/missing
SpeakV1WarningEvent.code
Field required [type=missing, input_value={'type': 'Warning', 'warn...lease try again later.'}, input_type=dict]
For further information visit https://errors.pydantic.dev/2.11/v/missing

But in the previous SDK, it just handled this warning message correctly/gracefully.
previous SDK:

async def _process_text(self, message: Union[str, bytes]) -> None:
  ...
  data = json.loads(message)
  response_type = data.get("type")
  ...
  match response_type:
    ...
    case SpeakWebSocketEvents.Warning:
      war_warning: WarningResponse = WarningResponse.from_json(message)
      self._logger.verbose("WarningResponse: %s", war_warning)
      await self._emit(
        SpeakWebSocketEvents(SpeakWebSocketEvents.Warning),
        warning=war_warning,
        **dict(cast(Dict[Any, Any], self._kwargs)),
      )
    ...
@dataclass
class WarningResponse(BaseResponse):
    """
    Warning Message from the Deepgram Platform
    """

    warn_code: str = ""
    warn_msg: str = ""
    type: str = ""

In addition to this property name discrepancy, I see previous SDK uses cls.from_dict, which I think won't hard fail even property names mismatch, while the new SDK uses pydantic, which I think is more strict about this.

Transport

HTTP

API endpoint / path

speak.v1.connect

Model(s) used

aura-2

How often?

Always

Is this a regression?

  • Yes, it worked in an earlier version

Last working SDK version (if known)

4.8.1

SDK version

5.1.0

Python version

3.11

Install method

None

OS

Linux (x86_64)

Environment details


Link to minimal repro (optional)

No response

Session ID (optional)

No response

Project ID (optional)

No response

Request ID (optional)

No response

Code of Conduct

  • I agree to follow this project’s Code of Conduct

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions