{"record":{"id":"031dc20637764d19","repo":"chenhg5/cc-connect","slug":"token-request-returned-d-s","errorCode":null,"errorMessage":"token request returned %d: %s","messagePattern":"token request returned (.+?): (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/qqbot/qqbot.go","lineNumber":582,"sourceCode":"// ---------------------------------------------------------------------------\n// OAuth2 Token Management\n// ---------------------------------------------------------------------------\n\nfunc (p *Platform) refreshToken() error {\n\tbody, _ := json.Marshal(map[string]string{\n\t\t\"appId\":        p.appID,\n\t\t\"clientSecret\": p.appSecret,\n\t})\n\n\tresp, err := core.HTTPClient.Post(tokenURL, \"application/json\", bytes.NewReader(body))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"token request failed: %w\", err)\n\t}\n\tdefer resp.Body.Close()\n\n\tif resp.StatusCode != http.StatusOK {\n\t\traw, _ := io.ReadAll(resp.Body)\n\t\treturn fmt.Errorf(\"token request returned %d: %s\", resp.StatusCode, raw)\n\t}\n\n\tvar result struct {\n\t\tAccessToken string `json:\"access_token\"`\n\t\tExpiresIn   string `json:\"expires_in\"`\n\t}\n\tif err := json.NewDecoder(resp.Body).Decode(&result); err != nil {\n\t\treturn fmt.Errorf(\"token response decode: %w\", err)\n\t}\n\tif result.AccessToken == \"\" {\n\t\treturn fmt.Errorf(\"empty access_token in response\")\n\t}\n\n\tvar expiresSec int\n\t_, _ = fmt.Sscanf(result.ExpiresIn, \"%d\", &expiresSec)\n\tif expiresSec <= 0 {\n\t\texpiresSec = 7200\n\t}","sourceCodeStart":564,"sourceCodeEnd":600,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/qqbot/qqbot.go#L564-L600","documentation":"The OAuth token endpoint answered, but with a non-200 status. refresh token returns this error including the status code and the raw response body (platform/qqbot/qqbot.go:582). Almost always this means the appId/clientSecret credentials were rejected (401/400) or the service is degraded (5xx).","triggerScenarios":"refreshToken gets resp.StatusCode != 200: wrong or revoked appSecret (401/400), malformed appId, QQ Bot API outage (500/503), or rate limiting on the token endpoint.","commonSituations":"Typo'd or rotated-out appSecret in config.toml; QQ open-platform app disabled; clock/host issues causing 4xx; shared IP rate-limited by QQ.","solutions":["Read the status code and body in the error: 401/400 means fix appId/clientSecret in config.toml.","Confirm the app is still active on the QQ open platform console and the secret has not been rotated.","If 5xx, retry later — the QQ Bot service may be degraded.","Avoid tight refresh loops; the platform already refreshes lazily, so hammering the endpoint can trigger rate limits."],"exampleFix":"// before\n\"qqbot\": { appId = \"old-id\", appSecret = \"stale-secret\" }\n// after\n\"qqbot\": { appId = \"<current-app-id>\", appSecret = \"<current-secret-from-qq-console>\" }","handlingStrategy":"try-catch","validationCode":"// validate credentials at startup before wiring the platform:\nif appID == \"\" || appSecret == \"\" { return fmt.Errorf(\"qqbot appId/appSecret required in config\") }","typeGuard":null,"tryCatchPattern":"if err := platform.Start(ctx); err != nil {\n    if strings.Contains(err.Error(), \"token request returned 401\") || strings.Contains(err.Error(), \"token request returned 400\") {\n        return fmt.Errorf(\"qqbot credentials rejected — check appId/appSecret: %w\", err)\n    }\n    return err\n}","preventionTips":["Store appId/appSecret in config.toml and rotate them in the QQ console before old secrets expire.","Distinguish 4xx (credentials — fix config) from 5xx (service — retry later) when reading the error.","Never commit secrets; load them from env/secret store to avoid accidental revocation/leaks.","Check startup logs once at deploy time; a bad secret fails fast on the first token request."],"tags":["oauth","qqbot","http-error","auth","token"],"backgroundTag":"oauth-token-exchange-failed","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}