{"record":{"id":"e8093aa86764c085","repo":"sipeed/picoclaw","slug":"failed-to-get-wecom-qr-code-response-missing-scod","errorCode":null,"errorMessage":"failed to get WeCom QR code: response missing scode or auth_url","messagePattern":"failed to get WeCom QR code: response missing scode or auth_url","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/picoclaw/internal/auth/wecom.go","lineNumber":269,"sourceCode":"func fetchWeComQRCode(ctx context.Context, opts wecomQRFlowOptions) (wecomQRSession, error) {\n\tgenerateURL, err := buildWeComQRGenerateURL(opts.GenerateURL, opts.SourceID, wecomPlatformCode())\n\tif err != nil {\n\t\treturn wecomQRSession{}, err\n\t}\n\n\tvar resp wecomQRGenerateResponse\n\tif err := doWeComJSONGet(ctx, opts.HTTPClient, generateURL, &resp); err != nil {\n\t\treturn wecomQRSession{}, fmt.Errorf(\"failed to get WeCom QR code: %w\", err)\n\t}\n\tif resp.ErrCode != 0 {\n\t\treturn wecomQRSession{}, fmt.Errorf(\n\t\t\t\"failed to get WeCom QR code: errcode=%d errmsg=%s\",\n\t\t\tresp.ErrCode,\n\t\t\tresp.ErrMsg,\n\t\t)\n\t}\n\tif resp.Data.SCode == \"\" || resp.Data.AuthURL == \"\" {\n\t\treturn wecomQRSession{}, fmt.Errorf(\"failed to get WeCom QR code: response missing scode or auth_url\")\n\t}\n\n\treturn wecomQRSession{\n\t\tSCode:   resp.Data.SCode,\n\t\tAuthURL: resp.Data.AuthURL,\n\t}, nil\n}\n\nfunc pollWeComQRCodeResult(ctx context.Context, opts wecomQRFlowOptions, scode string) (wecomQRBotInfo, error) {\n\tif strings.TrimSpace(scode) == \"\" {\n\t\treturn wecomQRBotInfo{}, fmt.Errorf(\"missing WeCom QR scode\")\n\t}\n\n\ttimeoutCtx, cancel := context.WithTimeout(ctx, opts.PollTimeout)\n\tdefer cancel()\n\n\tvar scannedPrinted bool\n","sourceCodeStart":251,"sourceCodeEnd":287,"githubUrl":"https://github.com/sipeed/picoclaw/blob/49183d7e8daed0dba89ddbb6fcb60089401d9680/cmd/picoclaw/internal/auth/wecom.go#L251-L287","documentation":"The generate endpoint returned errcode 0 (success) but the data payload lacked scode or auth_url, the two fields the QR session needs. This is a contract violation by the relay: the response parsed as JSON and claimed success, yet the session fields are empty strings.","triggerScenarios":"Relay API version drift where field names change (e.g. scode renamed); relay degraded and returning a success envelope with empty data; an interception proxy returning a stubbed JSON body with matching outer shape.","commonSituations":"picoclaw binary older than a relay-side response schema change; transparent proxy injecting its own JSON; relay partial outage.","solutions":["Update picoclaw to the latest version to match the current relay response schema","Inspect the raw response with curl to confirm the relay is sending scode and auth_url","Retry after a short wait in case of relay degradation","If the relay schema truly changed, pin the compatible picoclaw release or report the break upstream"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Treat an empty session payload as retryable instead of hard-failing\nif resp.Data.SCode == \"\" || resp.Data.AuthURL == \"\" {\n\t// retry generate once before giving up\n}","typeGuard":"func hasQRSession(resp wecomQRGenerateResponse) bool {\n\treturn resp.ErrCode == 0 && resp.Data.SCode != \"\" && resp.Data.AuthURL != \"\"\n}","tryCatchPattern":null,"preventionTips":["Pin a picoclaw version known compatible with the current relay schema","Retrying once masks most transient empty-payload responses"],"tags":["go","wecom","api-contract","validation"],"backgroundTag":null,"analyzedSha":"49183d7e8daed0dba89ddbb6fcb60089401d9680","analyzedAt":"2026-08-15T21:55:41.315Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}