#3365·picoclaw

QQ channel fails with 401 "Authorization参数格式错误" — root cause in botgo v0.2.1 + resty >= v2.17

Author: crazysarahCreated Sep 4, 2026Updated Sep 14, 2026
Labelsstale

Environment

  • Device: Orange Pi 3B (RK3566, aarch64)
  • picoclaw: nightly build (--version reports 0.3.1), module github.com/sipeed/picoclaw
  • botgo: github.com/tencent-connect/botgo v0.2.1 (latest available)
  • resty: github.com/go-resty/resty/v2 v2.17.1 (indirect dependency)

Symptom

The QQ channel fails to start. The gateway log shows:

failed to get websocket info: HTTP 401
code:11241  err_code:40011005
message: "请求头Authorization参数格式错误"

The credentials are valid — calling POST https://bots.qq.com/app/getAppAccessToken with the same appId/clientSecret returns a valid access_token.

What is actually sent (MITM capture)

Intercepting the real TLS traffic from picoclaw to api.sgroup.qq.com:

GET /gateway/bot HTTP/1.1
User-Agent:    BotGoSDK/v0.0.2
Authorization: Bearer VEf7J-...        <-- WRONG, must be "QQBot"
X-Union-Appid: 1903802227

Cross-check on the same machine/token:

Authorization header Result
QQBot <token> 200, gateway returned
Bearer <token> 401 / 11241 / 40011005
empty 401 / 11241 / 40011005

Root cause (upstream, in botgo)

This is not a bug in picoclaw's own code — picoclaw is a victim of an incompatibility between botgo v0.2.1 and resty v2.17.1.

  1. botgo's token source sets the correct type: TokenType: TypeQQBot ("QQBot").

  2. botgo openapi/v1/openapi.go setupClient() sets the auth scheme inside an OnBeforeRequest hook on the resty Client, and discards the *resty.Request argument:

    go
    OnBeforeRequest(func(c *resty.Client, _ *resty.Request) error {
        tk, err := o.tokenSource.Token()
        ...
        c.SetAuthScheme(tk.TokenType)   // Client-level, set AFTER R() ran
        c.SetAuthToken(tk.AccessToken)
    })
  3. resty >= v2.17 snapshots AuthScheme: c.AuthScheme (default "Bearer") into the Request at Client.R() time, and its addCredentials() now reads only the request-level scheme. The old client-level fallback (else if !IsStringEmpty(c.AuthScheme)) was removed. So the request that was already built keeps "Bearer" regardless of the later c.SetAuthScheme(...).

Full source-level analysis (with the exact resty v2.11.0 vs v2.17.1 diffs) is available if needed.

Impact

Every project that combines botgo v0.2.1 (the only/latest release) with resty >= v2.17.0 has a completely broken QQ channel.

Suggested fixes (for picoclaw maintainers)

  • Pin the indirect dependency to a resty version that still has the client-level AuthScheme fallback (e.g. v2.16.x) — please verify the fallback branch exists in the chosen version — OR

  • replace botgo with a fork that sets the scheme on the *resty.Request:

    go
    OnBeforeRequest(func(_ *resty.Client, req *resty.Request) error {
        tk, err := o.tokenSource.Token()
        ...
        req.SetAuthScheme(tk.TokenType)   // request-level
        req.SetAuthToken(tk.AccessToken)
    })

    This is correct on both old and new resty (request-level SetAuthScheme overrides the client-level one).

I'm also submitting a PR with the 3-line fix to tencent-connect/botgo.

Note: the QQ channel (pkg/channels/qq/) only exists on main/nightly, not in the v0.3.1 tag — worth keeping in mind if anyone tries to reproduce on the tagged release.