Skip to content

fix(qqbot): use resume for 4009 session timeout instead of re-identify - #21073

Closed
husttsq wants to merge 2 commits into
NousResearch:mainfrom
husttsq:fix/qqbot-4009-session-timeout-resume
Closed

fix(qqbot): use resume for 4009 session timeout instead of re-identify#21073
husttsq wants to merge 2 commits into
NousResearch:mainfrom
husttsq:fix/qqbot-4009-session-timeout-resume

Conversation

@husttsq

@husttsq husttsq commented May 7, 2026

Copy link
Copy Markdown

Problem

QQ Bot WebSocket disconnects every 30 minutes with code 4009 (Session timed out). The adapter incorrectly clears session_id and last_seq, forcing a full re-identify instead of resume.

Fix

  • Preserve session_id and last_seq on 4009 errors
  • Let reconnect flow use Resume (op 6) instead of Identify (op 2)

References

When QQ Bot WebSocket disconnects with code 4009 (Session timed out),
the adapter was clearing session_id and last_seq, forcing a full
re-identify on reconnect. This is incorrect per QQ's official docs.

QQ docs state 4009 should use Resume (op 6) to restore the session,
not re-identify (op 2). This fix:
- Preserves session_id and last_seq on 4009 errors
- Allows the reconnect flow to send Resume instead of Identify
- Reduces recovery time and message loss during 30-min timeouts

Reference: https://bot.q.qq.com/wiki/develop/api-v2/dev-prepare/error-trace/websocket.html
See also: openclaw/openclaw#65579
@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists platform/qqbot QQ Bot adapter comp/gateway Gateway runner, session dispatch, delivery labels May 7, 2026

@Bartok9 Bartok9 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verified the fix against the surrounding reconnect logic in adapter.py.

The _handle_dispatch() Hello handler at line 742:

if self._session_id and self._last_seq is not None:
    self._create_task(self._send_resume())

…already selects Resume vs Identify based purely on whether session_id / last_seq are set. So the fix is correct: removing 4009 from the clear session block is all that's needed.

One thought: the inline comment # Keep session_id and last_seq for resume is good documentation but could be even clearer — the reader has to scroll down to see when resume fires. A one-liner like:

# 4009 = Session timed out → preserve state; next Hello will trigger _send_resume() (op 6)

would tie the behavior together without having to trace the code path. Minor suggestion, not blocking.

@Bartok9

Bartok9 commented May 7, 2026

Copy link
Copy Markdown
Contributor

Verified the fix against the surrounding reconnect logic in adapter.py.

The Hello handler (~line 742) already selects Resume vs Identify based purely on whether session_id / last_seq are set:

if self._session_id and self._last_seq is not None:
    self._create_task(self._send_resume())

So removing 4009 from the 'clear session' block is all that's needed — correct and minimal.

One suggestion: the inline comment # Keep session_id and last_seq for resume is good but could tie back to when resume fires:

# 4009 = Session timed out → preserve state; the next Hello will trigger _send_resume() (op 6)

Minor — not blocking.

Improve inline comments to explain when resume fires (next Hello
triggers _send_resume op 6) instead of just saying 'preserve state'.
Also split 4009 out of the docstring's 'session invalid' group since
it now has distinct behavior.
@teknium1

Copy link
Copy Markdown
Contributor

Automated hermes-sweeper review: this fix is already present on current main.

Evidence:

  • gateway/platforms/qqbot/adapter.py:600 documents that 4009 is not included in the session-clearing path because it is resumable and should preserve session state.
  • gateway/platforms/qqbot/adapter.py:603 shows the branch that clears self._session_id / self._last_seq; it includes 4006, 4007, and 4900-4913, but not 4009.
  • gateway/platforms/qqbot/adapter.py:828 sends Resume when self._session_id and self._last_seq are still set, matching the reconnect behavior discussed in this PR.
  • The implementation landed in commit a54f5afc7086ffe14bc5a46d1e56e835c61092e4 via merged PR fix(qqbot): salvage 4 fixes from #27944 (intent, op 7/9, filename, SILK) #30843, and is contained in release tag v2026.5.28.

Thanks for the focused QQBot fix and for the review follow-up here; the same 4009 resume behavior has since been salvaged onto main.

@teknium1 teknium1 closed this Jun 11, 2026
@teknium1 teknium1 added the sweeper:implemented-on-main Sweeper: behavior already present on current main label Jun 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/gateway Gateway runner, session dispatch, delivery P2 Medium — degraded but workaround exists platform/qqbot QQ Bot adapter sweeper:implemented-on-main Sweeper: behavior already present on current main type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants