hermes - 💡(How to fix) Fix QQ Bot: approval button clicks rejected — session_key uses dm as chat_id instead of user openid [2 pull requests]

Official PRs (…)
ON THIS PAGE

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

Root Cause

Root cause (adapter.py:1058-1086)

def _parse_gateway_session_key(session_key: str) -> Optional[Dict[str, str]]:
    parts = str(session_key or "").split(":")
    parsed = {
        "platform": parts[2],
        "chat_type": parts[3],   # "dm" for c2c — WRONG: this is the literal string
        "chat_id": parts[4],     # "dm" — not the user's openid
    }
    if len(parts) > 5:
        parsed["user_id"] = parts[5]   # actual openid lives here
    return parsed

Fix Action

Fixed

Code Example

WARNING Rejected unauthorized approval click for session agent:main:qqbot:dm:E2FDAAE015E3CA4A24137B9F5E46405F (operator=E2FDAAE015E3CA4A24137B9F5E46405F)

---

def _parse_gateway_session_key(session_key: str) -> Optional[Dict[str, str]]:
    parts = str(session_key or "").split(":")
    parsed = {
        "platform": parts[2],
        "chat_type": parts[3],   # "dm" for c2c — WRONG: this is the literal string
        "chat_id": parts[4],     # "dm" — not the user's openid
    }
    if len(parts) > 5:
        parsed["user_id"] = parts[5]   # actual openid lives here
    return parsed

# In _is_authorized_interaction_for_session (c2c path):
chat_id = parsed.get("chat_id", "")  # = "dm"
return bool(chat_id) and operator == chat_id  # operator(openid) == "dm"False

---

if chat_type == "c2c":
    session_user = str(parsed.get("user_id", "")).strip()
    return bool(session_user) and operator == session_user
RAW_BUFFERClick to expand / collapse

Describe the bug When Hermes QQ Bot receives a C2C (private) message and the dangerous-command approval flow triggers, the approval keyboard is rendered with session_key = agent:main:qqbot:dm:E2FDAAE015E3CA4A24137B9F5E46405F. The dm substring occupies the chat_id position (parts[4]), and the user's openid ends up in parts[5].

When the user clicks the approval button, the adapter's _is_authorized_interaction_for_session check compares operator == chat_id, i.e. the user's openid vs the string "dm". This is never equal, so every approval click is rejected with:

WARNING Rejected unauthorized approval click for session agent:main:qqbot:dm:E2FDAAE015E3CA4A24137B9F5E46405F (operator=E2FDAAE015E3CA4A24137B9F5E46405F)

The C2C message is otherwise received and processed correctly — only the approval button click is broken.

Environment

  • Hermes profile: arara
  • QQ App ID: 1903906963
  • QQ DM policy: pairing
  • approvals.mode: manual

To reproduce

  1. Send any C2C message to the QQ bot that triggers a dangerous command approval
  2. An inline keyboard with 3 buttons appears
  3. Click any button — immediately rejected

Expected behavior The operator field from the QQ interaction event should be compared against the correct user identifier in the session_key (parts[5] for c2c), not parts[4] which is the literal string "dm".

Root cause (adapter.py:1058-1086)

def _parse_gateway_session_key(session_key: str) -> Optional[Dict[str, str]]:
    parts = str(session_key or "").split(":")
    parsed = {
        "platform": parts[2],
        "chat_type": parts[3],   # "dm" for c2c — WRONG: this is the literal string
        "chat_id": parts[4],     # "dm" — not the user's openid
    }
    if len(parts) > 5:
        parsed["user_id"] = parts[5]   # actual openid lives here
    return parsed

# In _is_authorized_interaction_for_session (c2c path):
chat_id = parsed.get("chat_id", "")  # = "dm"
return bool(chat_id) and operator == chat_id  # operator(openid) == "dm" → False

Suggested fix For c2c sessions, the authorization check should compare operator == user_id (parts[5]), not operator == chat_id (parts[4]):

if chat_type == "c2c":
    session_user = str(parsed.get("user_id", "")).strip()
    return bool(session_user) and operator == session_user

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

hermes - 💡(How to fix) Fix QQ Bot: approval button clicks rejected — session_key uses dm as chat_id instead of user openid [2 pull requests]