{"record":{"id":"42813444680fea2d","repo":"Tencent/WeKnora","slug":"unsupported-qqbot-mode-s-only-websocket-is-supp","errorCode":null,"errorMessage":"unsupported qqbot mode: %s (only websocket is supported)","messagePattern":"unsupported qqbot mode: (.+?) \\(only websocket is supported\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/im/qqbot/factory.go","lineNumber":20,"sourceCode":"\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/Tencent/WeKnora/internal/im\"\n\t\"github.com/Tencent/WeKnora/internal/logger\"\n)\n\nfunc NewFactory() im.AdapterFactory {\n\treturn func(factoryCtx context.Context, channel *im.IMChannel, msgHandler func(context.Context, *im.IncomingMessage) error) (im.Adapter, context.CancelFunc, error) {\n\t\tcreds, err := im.ParseCredentials(channel.Credentials)\n\t\tif err != nil {\n\t\t\treturn nil, nil, fmt.Errorf(\"parse qqbot credentials: %w\", err)\n\t\t}\n\n\t\tmode := im.ResolveMode(channel, \"websocket\")\n\t\tif mode != \"websocket\" {\n\t\t\treturn nil, nil, fmt.Errorf(\"unsupported qqbot mode: %s (only websocket is supported)\", mode)\n\t\t}\n\n\t\tclient, err := NewClient(\n\t\t\tim.GetString(creds, \"app_id\"),\n\t\t\tim.GetString(creds, \"client_secret\"),\n\t\t\tim.GetString(creds, \"api_base_url\"),\n\t\t\tim.GetString(creds, \"gateway_url\"),\n\t\t)\n\t\tif err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\n\t\tlongConn := NewLongConnClient(client, msgHandler)\n\t\twsCtx, wsCancel := context.WithCancel(context.Background())\n\t\tgo func() {\n\t\t\tif err := longConn.Start(wsCtx); err != nil && wsCtx.Err() == nil {\n\t\t\t\tlogger.Errorf(context.Background(), \"[IM] QQBot long connection stopped for channel %s: %v\", channel.ID, err)\n\t\t\t}","sourceCodeStart":2,"sourceCodeEnd":38,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/im/qqbot/factory.go#L2-L38","documentation":"The QQ bot adapter factory in internal/im/qqbot/factory.go only supports the 'websocket' connection mode. The channel's configured mode is resolved via im.ResolveMode (default 'websocket'), and if it resolves to anything else (e.g. 'webhook'), construction of the adapter fails immediately with this wrapped error.","triggerScenarios":"Creating/starting a QQ channel whose credentials resolve a mode other than 'websocket' — e.g. setting mode=webhook in the channel config or a credentials key that ResolveMode reads as a non-websocket mode.","commonSituations":"Copying a Telegram/Slack channel config (which supports webhook) and reusing it for QQ; a config migration that sets a webhook URL for QQ; typos in the mode field that resolve to a non-websocket string.","solutions":["Set the channel's mode to \"websocket\" (or omit it to get the websocket default)","Remove any webhook URL/mode fields copied from other platform configs","If webhook mode is truly needed, verify the library version supports it for QQ — it does not, so switch platform or implement a websocket-only setup"],"exampleFix":"// before\n{\"platform\":\"qqbot\",\"mode\":\"webhook\",\"credentials\":{...}}\n// after\n{\"platform\":\"qqbot\",\"mode\":\"websocket\",\"credentials\":{\"app_id\":\"...\",\"client_secret\":\"...\"}}","handlingStrategy":"validation","validationCode":"mode := im.ResolveMode(channel, \"websocket\")\nif mode != \"websocket\" {\n    return fmt.Errorf(\"qqbot channel %s requires websocket mode, got %q\", channel.ID, mode)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always set mode:\"websocket\" (or omit mode) for qqbot channels","Never copy webhook config from other platforms to qqbot","Validate channel configs at creation time, not at adapter start"],"tags":["qqbot","configuration","unsupported-mode"],"backgroundTag":"unsupported-mode-configured","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}