{"record":{"id":"8f5a8d85b144803f","repo":"sipeed/picoclaw","slug":"failed-to-query-wecom-qr-result-errcode-d-errmsg","errorCode":null,"errorMessage":"failed to query WeCom QR result: errcode=%d errmsg=%s","messagePattern":"failed to query WeCom QR result: errcode=(.+?) errmsg=(.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/picoclaw/internal/auth/wecom.go","lineNumber":337,"sourceCode":"\t\t\t}\n\t\t\treturn wecomQRBotInfo{}, timeoutCtx.Err()\n\t\tcase <-time.After(opts.PollInterval):\n\t\t}\n\t}\n}\n\nfunc queryWeComQRCodeStatus(ctx context.Context, opts wecomQRFlowOptions, scode string) (wecomQRQueryResponse, error) {\n\tqueryURL, err := buildWeComQRQueryURL(opts.QueryURL, scode)\n\tif err != nil {\n\t\treturn wecomQRQueryResponse{}, err\n\t}\n\n\tvar resp wecomQRQueryResponse\n\tif err := doWeComJSONGet(ctx, opts.HTTPClient, queryURL, &resp); err != nil {\n\t\treturn wecomQRQueryResponse{}, fmt.Errorf(\"failed to query WeCom QR result: %w\", err)\n\t}\n\tif resp.ErrCode != 0 {\n\t\treturn wecomQRQueryResponse{}, fmt.Errorf(\n\t\t\t\"failed to query WeCom QR result: errcode=%d errmsg=%s\",\n\t\t\tresp.ErrCode,\n\t\t\tresp.ErrMsg,\n\t\t)\n\t}\n\n\treturn resp, nil\n}\n\nfunc buildWeComQRGenerateURL(baseURL, sourceID string, platformCode int) (string, error) {\n\tu, err := url.Parse(baseURL)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"invalid WeCom QR generate URL: %w\", err)\n\t}\n\n\tquery := u.Query()\n\tquery.Set(\"source\", sourceID)\n\tquery.Set(\"sourceID\", sourceID)","sourceCodeStart":319,"sourceCodeEnd":355,"githubUrl":"https://github.com/sipeed/picoclaw/blob/49183d7e8daed0dba89ddbb6fcb60089401d9680/cmd/picoclaw/internal/auth/wecom.go#L319-L355","documentation":"The QR status query endpoint returned HTTP 200 with a non-zero errcode in the JSON body. The relay rejected the poll itself — most commonly an invalid or already-consumed scode — and the numeric code plus server errmsg are embedded in the error text.","triggerScenarios":"Polling with a scode that expired or was invalidated server-side (a newer QR generated for the same source); relay garbage-collected the session between polls; source throttling returning an error code.","commonSituations":"Two login sessions racing; long pause between generate and poll letting the relay purge the scode; relay restart dropping in-memory sessions.","solutions":["Re-run the login to obtain a fresh scode and keep exactly one session active","Match the errcode against the relay's documented codes (auth-token-invalid style codes mean the scode is dead; throttle codes mean back off)","Retry after a minute if the code indicates throttling","Update picoclaw if the relay changed session semantics between versions"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":"func isInvalidScode(err error) bool {\n\treturn err != nil && strings.Contains(err.Error(), \"failed to query WeCom QR result: errcode=\")\n}","tryCatchPattern":"if resp.ErrCode != 0 {\n\tif isThrottleCode(resp.ErrCode) {\n\t\t// back off one interval and keep polling\n\t} else {\n\t\treturn wecomQRQueryResponse{}, fmt.Errorf(\"failed to query WeCom QR result: errcode=%d errmsg=%s\", resp.ErrCode, resp.ErrMsg)\n\t}\n}","preventionTips":["Avoid concurrent login sessions that invalidate each other's scode","Log the errcode to distinguish session-death from throttling"],"tags":["go","wecom","api","error-code","polling"],"backgroundTag":null,"analyzedSha":"49183d7e8daed0dba89ddbb6fcb60089401d9680","analyzedAt":"2026-08-15T21:55:41.315Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}