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.
-
botgo's token source sets the correct type: TokenType: TypeQQBot ("QQBot").
-
botgo openapi/v1/openapi.go setupClient() sets the auth scheme inside an OnBeforeRequest hook on the resty Client, and discards the *resty.Request argument:
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)
})
-
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:
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.
Environment
--versionreports0.3.1), modulegithub.com/sipeed/picoclawgithub.com/tencent-connect/botgo v0.2.1(latest available)github.com/go-resty/resty/v2 v2.17.1(indirect dependency)Symptom
The QQ channel fails to start. The gateway log shows:
The credentials are valid — calling
POST https://bots.qq.com/app/getAppAccessTokenwith the sameappId/clientSecretreturns a validaccess_token.What is actually sent (MITM capture)
Intercepting the real TLS traffic from picoclaw to
api.sgroup.qq.com:Cross-check on the same machine/token:
QQBot <token>Bearer <token>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.1andresty v2.17.1.botgo's token source sets the correct type:
TokenType: TypeQQBot("QQBot").botgo
openapi/v1/openapi.gosetupClient()sets the auth scheme inside anOnBeforeRequesthook on the resty Client, and discards the*resty.Requestargument:resty >= v2.17 snapshots
AuthScheme: c.AuthScheme(default"Bearer") into the Request atClient.R()time, and itsaddCredentials()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 laterc.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
AuthSchemefallback (e.g.v2.16.x) — please verify the fallback branch exists in the chosen version — ORreplacebotgo with a fork that sets the scheme on the*resty.Request:This is correct on both old and new resty (request-level
SetAuthSchemeoverrides 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 onmain/nightly, not in thev0.3.1tag — worth keeping in mind if anyone tries to reproduce on the tagged release.