OpenClaw + QQ plugin integration and ultra-long troubleshooting postmortem (full process)

OpenClaw + QQ Plugin Integration and Extra-Long Troubleshooting Postmortem (End-to-End)

Note: This postmortem is organized according to the steps actually executed, focusing on the full process from integration and joint debugging to locating the core issue, as well as each key conclusion.

I. Background and Goals

The goal this time was to connect OpenClaw to the QQ channel (based on NapCat + the openclaw_qq plugin) and achieve:

  • Normal send/receive for QQ private chats and group chats
  • Conversation routing and WebUI records visible
  • Admin/blacklist policies controllable (to prevent Token abuse)
  • Configuration can be stably saved in Control UI

II. Environment and Timeline (Rough)

Based on gateway log timestamps, this investigation spanned multiple phases, with continuous high-intensity troubleshooting for several hours (about 4+ hours).

III. Main Workflow (By Phase)

1) QQ Channel Integration and Basic Joint Debugging

I first completed the basic deployment of the QQ plugin and NapCat:

  • Install and enable the openclaw_qq plugin
  • Deploy NapCat using Docker
  • Fix the NapCat connection mode to Forward WS Server (OpenClaw connects in as the client)
  • After aligning the OneBot Token and account, the QQ channel status returned to OK

2) Conversation and Routing Issue Fixes

During joint debugging, there was a phenomenon where “QQ conversations got mixed into the main conversation/TG conversation”, so I fixed routing:

  • Fix QQ group/direct route parsing
  • Prevent QQ writes from overwriting main conversation metadata
  • Ensure QQ and TG conversations can be separated and traced

Result: QQ conversation visibility in the WebUI improved significantly.

3) Context and Duplicate Message Policy Adjustments

To address the issue of “QQ bringing a long history every time causing noise”:

  • Change the default historyLimit to 0
  • Document clearly: by default rely on the OpenClaw conversation system, do not force concatenating the group original text
  • Only enable history concatenation when the user explicitly needs it

At the same time, I fixed logic related to repeated triggers and repeated prompts:

  • Adjust the admin restriction check order to: trigger conditions first (@/keywords) and then authorization
  • Add cooldown debouncing to non-admin prompts (default 10 seconds)
  • Fix a possible prompt loop in reply-to-bot scenarios

4) Admin/Blacklist Capability Enhancements

To prevent abuse, I added and strengthened capabilities:

  • adminOnlyChat
  • notifyNonAdminBlocked
  • nonAdminBlockedMessage
  • blockedNotifyCooldownMs

The blacklist logic was ultimately confirmed as:

  • Messages from users that hit blockedUsers are ignored directly (no reply, no prompt)

5) Control UI and Configuration Saving Issue (Key)

The most time-consuming and most critical issue was:

  • On the /config page, changing only the QQ allow/deny list still reports invalid config
  • The error points to models.providers.*.models[0].maxTokens

Final conclusions after locating the issue:

  1. /config saves the whole package, not just submitting channels.qq
  2. During whole-package validation, if any field is abnormal, the entire save fails
  3. maxTokens is incorrectly processed in some paths (stringified / false-positive redaction), causing whole-package validation to fail
  4. So it looks like “changing the QQ number causes a model error”, but in essence it is “whole-package validation collateral damage”

IV. Why It Looks Like “Changing the QQ Number Drags in maxTokens”

In one sentence: not business coupling, but save-mechanism coupling.

  • You change the QQ fields
  • It triggers writing back the entire configuration
  • In the full configuration, the model field type drifts (e.g., maxTokens becomes a string/invalid)
  • Validation fails, and the error bubbles up to the frontend

V. Repo and Local Sync Actions

I continuously fixed issues in the plugin repository and pushed multiple times, including:

  • Admin policy fixes
  • Conversation routing fixes
  • Default value adjustments for history injection
  • Frontend schema compatibility improvements
  • Documentation enhancements (Chinese examples)
  • Added NapCat docker deployment files
  • Ignored runtime directories to prevent repo pollution

At the same time, local .openclaw/extensions/qq was kept in sync with the remote main branch.

VI. About “Can This Be Fully Solved by Only Changing the QQ Plugin”

Conclusion:

  • It can solve the QQ plugin’s internal behavior and most usability issues
  • But it cannot彻底 fix OpenClaw Core’s whole-package save pipeline problem from the plugin layer
  • Because models.* validation belongs to OpenClaw Core and is outside the QQ plugin’s scope

VII. Actionable Recommendations (Final)

Short-term Usable (No Core Changes)

  • Use the CLI to modify QQ allow/deny lists to avoid the /config whole-package save path:
openclaw config set channels.qq.admins '"1838552185"' --json
openclaw config set channels.qq.blockedUsers '"342571216"' --json
openclaw gateway restart

Mid-term Recommendation (Root Fix)

  • Wait for / follow up on OpenClaw’s official fix for this type of issue (maxTokens + redaction + config save)
  • Or submit a minimal reproduction and a patch PR to the official repo

VIII. Lessons Learned

  1. When troubleshooting the /config page, always think in terms of “whole-package validation”; don’t stare only at the changed item
  2. If configuration redaction uses broad matching (e.g., /token/i), it can false-positive match maxTokens
  3. For chat plugins, the authorization order (trigger first, then authorize) is critical; otherwise it will cause noise in groups
  4. Debouncing and deduplication must be enabled by default; otherwise group chats will quickly amplify issues