You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Symptom — After updating to v0.17.0, the QQ Bot never recovers after a disconnection. On the watcher-driven reconnect it crashes with TypeError: connect() got an unexpected keyword argument 'is_reconnect'.
Root cause — gateway/run.py::_connect_adapter_with_timeout() forwards is_reconnect to every adapter via adapter.connect(is_reconnect=is_reconnect) (lines 3194/3197), and _PlatformAdapter.connect declares the contract async def connect(self, *, is_reconnect: bool = False) (gateway/platforms/base.py:2675). QQAdapter.connect was the lone token-platform adapter still on the bare signature async def connect(self) (gateway/platforms/qqbot/adapter.py:281), so the forwarded keyword raised TypeError and the reconnect path aborted.
Evidence — grep is_reconnect gateway/platforms/*.py shows signal/weixin/whatsapp_cloud/bluebubbles/yuanbao/webhook/msgraph_webhook/api_server all accept the keyword; qqbot did not. The cold-boot first connect worked (the gateway only passes is_reconnect=True from the watcher at run.py:7009), which matches the reporter's "fails on reconnect" symptom exactly.
Fix + why this level — Align QQAdapter.connect with the PlatformAdapter.connect contract (*, is_reconnect: bool = False). QQ manages its own session resume/replay inside the listen loop via op 6 Resume (_send_resume, tracking _session_id/_last_seq), so the cold-boot handshake itself is unchanged; the flag is accepted for signature compatibility. Fixing at the adapter signature (rather than wrapping the call site in try/except TypeError in run.py) is correct because the base contract already mandates this signature for all adapters — the call site is right, the adapter was the outlier.
Scope / risk — One-line signature change plus a docstring note in qqbot/adapter.py. No behavioral change to the handshake; is_reconnect is intentionally not consumed because QQ resume is handled in the listen loop, not at connect. No other adapter touched.
Tests
Added TestConnectAcceptsIsReconnect in tests/gateway/test_qqbot.py:
test_connect_signature_accepts_is_reconnect_keyword — asserts the param exists, is keyword-only, defaults False.
test_connect_does_not_raise_typeerror_on_is_reconnect — calls connect(is_reconnect=True) (deps short-circuited) and asserts a graceful False, not a TypeError.
Both FAIL without the fix (TypeError) and pass with it.
$ .venv/bin/python -m pytest tests/gateway/test_qqbot.py -q
163 passed, 4 warnings in 3.49s
# without fix (signature reverted to `async def connect(self)`):
FAILED tests/gateway/test_qqbot.py::TestConnectAcceptsIsReconnect::test_connect_signature_accepts_is_reconnect_keyword
FAILED tests/gateway/test_qqbot.py::TestConnectAcceptsIsReconnect::test_connect_does_not_raise_typeerror_on_is_reconnect
2 failed in 0.25s
Duplicate of #52922 — same one-line is_reconnect keyword-only signature fix to QQAdapter.connect() (gateway/platforms/qqbot/adapter.py) for the same v0.17.0 reconnect regression (issue #52914 / #54679). #52922 (by iborazzi) is the earliest-open canonical fix; this is a saturated cluster (#53948, #54029, #54037, #53546 already marked duplicate of #52922). A human picks which to merge.
Confirmed duplicate of #52922 — thanks for the cross-reference. #52922 (iborazzi) is the earliest-open canonical fix for the same one-line keyword-only signature change. Closing this to keep the cluster clean and reduce triage load. Happy to leave the added TestConnectAcceptsIsReconnect regression tests as a follow-up if the merged PR doesn't include equivalent coverage.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
comp/gatewayGateway runner, session dispatch, deliveryduplicateThis issue or pull request already existsP2Medium — degraded but workaround existsplatform/qqbotQQ Bot adaptersweeper:risk-message-deliverySweeper risk: may drop, duplicate, misroute, or suppress messagestype/bugSomething isn't working
2 participants
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #54679.
Root Cause
Symptom — After updating to v0.17.0, the QQ Bot never recovers after a disconnection. On the watcher-driven reconnect it crashes with
TypeError: connect() got an unexpected keyword argument 'is_reconnect'.Root cause —
gateway/run.py::_connect_adapter_with_timeout()forwardsis_reconnectto every adapter viaadapter.connect(is_reconnect=is_reconnect)(lines 3194/3197), and_PlatformAdapter.connectdeclares the contractasync def connect(self, *, is_reconnect: bool = False)(gateway/platforms/base.py:2675).QQAdapter.connectwas the lone token-platform adapter still on the bare signatureasync def connect(self)(gateway/platforms/qqbot/adapter.py:281), so the forwarded keyword raisedTypeErrorand the reconnect path aborted.Evidence —
grep is_reconnect gateway/platforms/*.pyshows signal/weixin/whatsapp_cloud/bluebubbles/yuanbao/webhook/msgraph_webhook/api_server all accept the keyword; qqbot did not. The cold-boot first connect worked (the gateway only passesis_reconnect=Truefrom the watcher at run.py:7009), which matches the reporter's "fails on reconnect" symptom exactly.Fix + why this level — Align
QQAdapter.connectwith thePlatformAdapter.connectcontract (*, is_reconnect: bool = False). QQ manages its own session resume/replay inside the listen loop via op 6 Resume (_send_resume, tracking_session_id/_last_seq), so the cold-boot handshake itself is unchanged; the flag is accepted for signature compatibility. Fixing at the adapter signature (rather than wrapping the call site intry/except TypeErrorin run.py) is correct because the base contract already mandates this signature for all adapters — the call site is right, the adapter was the outlier.Scope / risk — One-line signature change plus a docstring note in qqbot/adapter.py. No behavioral change to the handshake;
is_reconnectis intentionally not consumed because QQ resume is handled in the listen loop, not at connect. No other adapter touched.Tests
Added
TestConnectAcceptsIsReconnectintests/gateway/test_qqbot.py:test_connect_signature_accepts_is_reconnect_keyword— asserts the param exists, is keyword-only, defaults False.test_connect_does_not_raise_typeerror_on_is_reconnect— callsconnect(is_reconnect=True)(deps short-circuited) and asserts a gracefulFalse, not aTypeError.Both FAIL without the fix (TypeError) and pass with it.