Description
When using DingTalkStreamClient and running client.start_forever(), if the underlying WebSocket encounters a network issue (such as TimeoutError during the opening handshake or HTTP 502 Bad Gateway from the DingTalk open connection gateway), the SDK attempts to catch and log the exception.
However, the logging statement in dingtalk_stream/stream.py uses incorrect string formatting parameters, which raises a TypeError: not all arguments converted during string formatting. This TypeError crashes the internal asyncio event loop and forces client.start_forever() to exit completely, rather than cleanly catching the network exception and attempting a reconnection.
Error Logs
Here is the core traceback showing the logging module crashing due to the incorrectly formatted logger call:
Traceback (most recent call last):
... (WebSockets TimeoutError or HTTP 502 traceback here) ...
File "/usr/local/lib/python3.12/site-packages/dingtalk_stream/stream.py", line 74, in start
async with websockets.connect(uri) as websocket:
File "/usr/local/lib/python3.12/site-packages/websockets/asyncio/client.py", line 590, in aenter
return await self
File "/usr/local/lib/python3.12/site-packages/websockets/asyncio/client.py", line 581, in await_impl
raise TimeoutError("timed out during opening handshake") from exc
TimeoutError: timed out during opening handshake
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/local/lib/python3.12/logging/init.py", line 1160, in emit
msg = self.format(record)
File "/usr/local/lib/python3.12/logging/init.py", line 999, in format
return fmt.format(record)
File "/usr/local/lib/python3.12/logging/init.py", line 703, in format
record.message = record.getMessage()
File "/usr/local/lib/python3.12/logging/init.py", line 392, in getMessage
msg = msg % self.args
TypeError: not all arguments converted during string formatting
Call stack:
... (Django/App call stack) ...
File "/app/ai/management/commands/dingtalk_stream.py", line 60, in handle
client.start_forever()
File "/usr/local/lib/python3.12/site-packages/dingtalk_stream/stream.py", line 142, in start_forever
asyncio.run(self.start())
... (Asyncio call stack) ...
File "/usr/local/lib/python3.12/asyncio/events.py", line 88, in _run
self._context.run(self._callback, *self._args)
File "/usr/local/lib/python3.12/site-packages/dingtalk_stream/stream.py", line 89, in start
self.logger.exception('unknown exception', e)
Message: 'unknown exception'
Arguments: (TimeoutError('timed out during opening handshake'),)
Root Cause
In dingtalk_stream/stream.py (around line 89), there is the following code snippet:
python
except Exception as e:
self.logger.exception('unknown exception', e)
The standard Python logging.exception() method expects the first argument to be a message string with formatting placeholders (like %s). Because the string 'unknown exception' does not contain any format specifiers, passing e as the second argument causes the logging module to raise a TypeError when it evaluates msg % self.args.
Since this occurs inside an asyncio task, the unhandled TypeError causes the entire event loop to crash, breaking the persistence of client.start_forever().
Suggested Fix
Update the logging statement in stream.py to use proper string formatting, or let the exception() method handle the traceback implicitly:
python
Option 1: Use proper formatting placeholders
self.logger.exception('unknown exception: %s', e)
Option 2: Let exception() handle the stack trace automatically without passing e as a positional argument
self.logger.exception('unknown exception')
Description
When using DingTalkStreamClient and running client.start_forever(), if the underlying WebSocket encounters a network issue (such as TimeoutError during the opening handshake or HTTP 502 Bad Gateway from the DingTalk open connection gateway), the SDK attempts to catch and log the exception.
However, the logging statement in dingtalk_stream/stream.py uses incorrect string formatting parameters, which raises a TypeError: not all arguments converted during string formatting. This TypeError crashes the internal asyncio event loop and forces client.start_forever() to exit completely, rather than cleanly catching the network exception and attempting a reconnection.
Error Logs
Here is the core traceback showing the logging module crashing due to the incorrectly formatted logger call:
Traceback (most recent call last):
... (WebSockets TimeoutError or HTTP 502 traceback here) ...
File "/usr/local/lib/python3.12/site-packages/dingtalk_stream/stream.py", line 74, in start
async with websockets.connect(uri) as websocket:
File "/usr/local/lib/python3.12/site-packages/websockets/asyncio/client.py", line 590, in aenter
return await self
File "/usr/local/lib/python3.12/site-packages/websockets/asyncio/client.py", line 581, in await_impl
raise TimeoutError("timed out during opening handshake") from exc
TimeoutError: timed out during opening handshake
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/local/lib/python3.12/logging/init.py", line 1160, in emit
msg = self.format(record)
File "/usr/local/lib/python3.12/logging/init.py", line 999, in format
return fmt.format(record)
File "/usr/local/lib/python3.12/logging/init.py", line 703, in format
record.message = record.getMessage()
File "/usr/local/lib/python3.12/logging/init.py", line 392, in getMessage
msg = msg % self.args
TypeError: not all arguments converted during string formatting
Call stack:
... (Django/App call stack) ...
File "/app/ai/management/commands/dingtalk_stream.py", line 60, in handle
client.start_forever()
File "/usr/local/lib/python3.12/site-packages/dingtalk_stream/stream.py", line 142, in start_forever
asyncio.run(self.start())
... (Asyncio call stack) ...
File "/usr/local/lib/python3.12/asyncio/events.py", line 88, in _run
self._context.run(self._callback, *self._args)
File "/usr/local/lib/python3.12/site-packages/dingtalk_stream/stream.py", line 89, in start
self.logger.exception('unknown exception', e)
Message: 'unknown exception'
Arguments: (TimeoutError('timed out during opening handshake'),)
Root Cause
In dingtalk_stream/stream.py (around line 89), there is the following code snippet:
python
except Exception as e:
self.logger.exception('unknown exception', e)
The standard Python logging.exception() method expects the first argument to be a message string with formatting placeholders (like %s). Because the string 'unknown exception' does not contain any format specifiers, passing e as the second argument causes the logging module to raise a TypeError when it evaluates msg % self.args.
Since this occurs inside an asyncio task, the unhandled TypeError causes the entire event loop to crash, breaking the persistence of client.start_forever().
Suggested Fix
Update the logging statement in stream.py to use proper string formatting, or let the exception() method handle the traceback implicitly:
python
Option 1: Use proper formatting placeholders
self.logger.exception('unknown exception: %s', e)
Option 2: Let exception() handle the stack trace automatically without passing
eas a positional argumentself.logger.exception('unknown exception')