Skip to content

RuntimeError: Task cannot await on itself when Ring sends a session close message (close callback re-enters RingWebRtcStream.close) #6

Description

@Siddharta84

Bug description

When the Ring server closes an active WebRTC live session (hang-up / session timeout), the reader task dies with RuntimeError: Task cannot await on itself and the exception is never retrieved. The close/error reason is also never forwarded to the on_message_callback, so the camera entity / card frontend never learns that the session ended (in my case: card buttons stayed greyed out and the card did not react until reload).

Environment

  • Home Assistant Core 2026.9.1 (pins ring-doorbell==0.9.14)
  • ring-intercom-video integration v0.6.0b1
  • python-ring-doorbell 0.9.14, Python 3.14
  • Device: Ring Intercom, audio-only variant (device_kind: intercom_handset_audio, audio_only: true)

Log output

2026-09-09 18:05:31.825 ERROR (MainThread) [homeassistant] Error doing job: Task exception was never retrieved (task: None)
Traceback (most recent call last):
  File "/usr/local/lib/python3.14/site-packages/ring_doorbell/webrtcstream.py", line 247, in reader
    await self.handle_message(message)
  File "/usr/local/lib/python3.14/site-packages/ring_doorbell/webrtcstream.py", line 423, in handle_message
    await self.handle_close_message(message)
  File "/usr/local/lib/python3.14/site-packages/ring_doorbell/webrtcstream.py", line 301, in handle_close_message
    await self._close(closed_by_self=True)
  File "/usr/local/lib/python3.14/site-packages/ring_doorbell/webrtcstream.py", line 378, in _close
    await close_cb()
  File "/config/custom_components/ring_intercom_camera/__init__.py", line 56, in _close_callback
    await self.close_webrtc_stream(session_id)
  File "/config/custom_components/ring_intercom_camera/__init__.py", line 77, in close_webrtc_stream
    await stream.close()
  File "/usr/local/lib/python3.14/site-packages/ring_doorbell/webrtcstream.py", line 370, in close
    await self._close(closed_by_self=False)
  File "/usr/local/lib/python3.14/site-packages/ring_doorbell/webrtcstream.py", line 392, in _close
    await read_task
RuntimeError: Task cannot await on itself: <Task pending name='Task-2498' coro=<RingWebRtcStream.reader() running at /usr/local/lib/python3.14/site-packages/ring_doorbell/webrtcstream.py:247>>

Root cause: re-entrant close

  1. Ring sends a session close message; the reader task receives it.
  2. RingWebRtcStream.handle_close_message() (webrtcstream.py:294) calls await self._close(closed_by_self=True).
  3. _close() invokes the integration's on_close_callback (webrtcstream.py:376-378) — still inside the reader task.
  4. The integration's callback (_close_callback → close_webrtc_stream, __init__.py:55-77) calls await stream.close() on the same stream.
  5. That second _close() reaches await read_task (webrtcstream.py:389-392) — but read_task is the task currently executing this code → RuntimeError: Task cannot await on itself.

Consequences:

  • The reader task crashes with an unretrieved exception on every server-initiated close.
  • handle_close_message() never reaches self._on_message_callback(error_message) (webrtcstream.py:302-306), so the close/error reason is never delivered to the frontend.

Suggested fix

Avoid re-entering close() from within the close callback. The integration already has sync_close_webrtc_stream (__init__.py:79-83) which uses RingWebRtcStream.sync_close() — that schedules the close in a separate task and avoids the self-await. So in close_webrtc_stream:

async def close_webrtc_stream(self, session_id):
    streams = _get_streams(self)
    stream = streams.pop(session_id, None)
    if stream:
        stream.sync_close()   # instead of: await stream.close()

Alternatively (or additionally) the lib could harden _close() itself, e.g. skip the await when re-entered from the reader: if not read_task.done() and read_task is not asyncio.current_task(): await read_task.

Reproduction

  1. Start a live session on an audio-only Intercom (card or the more-info dialog).
  2. End the session such that Ring sends the close message (hang up / let it time out) rather than closing only locally.
  3. Observe Error doing job: Task exception was never retrieved + the RuntimeError in the logs; frontend keeps showing the stale session state.

Happy to test a patched build. Thanks for the integration — audio-only support in 0.6.0b1 works great otherwise (stable sub-second round-trip audio).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions