{"record":{"id":"f554302b23d5eec6","repo":"chenhg5/cc-connect","slug":"qqbot-get-token-w","errorCode":null,"errorMessage":"qqbot: get token: %w","messagePattern":"qqbot: get token: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/qqbot/qqbot.go","lineNumber":316,"sourceCode":"\t\treturn \"\", fmt.Errorf(\"qqbot: upload rich media: empty file_info\")\n\t}\n\treturn result.FileInfo, nil\n}\n\n// apiRequestJSON is like apiRequest but also decodes the response body into result.\nfunc (p *Platform) apiRequestJSON(method, url string, body any, result any) error {\n\tvar bodyReader io.Reader\n\tif body != nil {\n\t\tdata, err := json.Marshal(body)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"qqbot: marshal body: %w\", err)\n\t\t}\n\t\tbodyReader = bytes.NewReader(data)\n\t}\n\n\ttoken, err := p.getAccessToken()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"qqbot: get token: %w\", err)\n\t}\n\n\treq, err := http.NewRequest(method, url, bodyReader)\n\tif err != nil {\n\t\treturn err\n\t}\n\treq.Header.Set(\"Authorization\", \"QQBot \"+token)\n\treq.Header.Set(\"Content-Type\", \"application/json\")\n\n\tresp, err := core.HTTPClient.Do(req)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"qqbot: api request failed: %w\", err)\n\t}\n\tdefer resp.Body.Close()\n\n\t// Retry once on 401\n\tif resp.StatusCode == http.StatusUnauthorized {\n\t\tif err := p.refreshToken(); err != nil {","sourceCodeStart":298,"sourceCodeEnd":334,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/qqbot/qqbot.go#L298-L334","documentation":"This error is raised inside apiRequestJSON when p.getAccessToken() fails before any HTTP request is made. getAccessToken fetches (and caches) the app-wide access token using the configured AppID/AppSecret; failure means credentials are wrong, the token endpoint is unreachable, or the cached token could not be refreshed. All qqbot API calls (sendMessage, uploadRichMedia, ackInteraction) funnel through here, so this blocks every outbound API interaction.","triggerScenarios":"Any of uploadRichMedia, ackInteraction, or sendMessage calls apiRequestJSON and getAccessToken returns an error: invalid AppID/AppSecret in config.toml, token endpoint unreachable, or token exchange rejected (e.g. wrong secret, suspended app).","commonSituations":"Misconfigured qqbot appId/appSecret in config.toml; credentials rotated in the QQ Open Platform console but not updated locally; network egress blocked to the QQ API host; app disabled or sandbox/scope restrictions.","solutions":["Verify appId and appSecret in the [platform.qqbot] config section against the QQ Open Platform console.","Test network reachability to the QQ API token endpoint from the host running cc-connect (curl the apiBase).","Run `cc-connect doctor` to check credentials and connectivity.","Check that the qqbot app is approved/enabled and the secret was not recently rotated.","Inspect the wrapped error text — it names the underlying cause (auth refused vs network timeout)."],"exampleFix":"// before (config.toml)\n[platforms.qqbot]\nappId = \"\"\nappSecret = \"stale-secret\"\n// after\n[platforms.qqbot]\nappId = \"123456789\"\nappSecret = \"current-secret-from-console\"","handlingStrategy":"validation","validationCode":"if cfg.QQBot.AppID == \"\" || cfg.QQBot.AppSecret == \"\" {\n    return fmt.Errorf(\"qqbot: appId/appSecret must be set in config\")\n}\nif err := doctorCheckEndpoint(qqbotTokenURL); err != nil {\n    return fmt.Errorf(\"qqbot: token endpoint unreachable: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"if err := p.SendFile(ctx, rctx, f); err != nil {\n    if strings.Contains(err.Error(), \"get token\") {\n        // credentials/network problem; do not retry blindly, alert + verify config\n        slog.Error(\"qqbot auth unavailable\", \"err\", err)\n    }\n}","preventionTips":["Validate appId/appSecret at startup, before accepting messages.","Run `cc-connect doctor` on deploy to catch credential problems early.","Alert on the first 'get token' failure — every subsequent send will fail too.","Keep credentials in sync after rotating them in the QQ console."],"tags":["qqbot","authentication","network","config"],"backgroundTag":"missing-credentials","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}