{"record":{"id":"c1d1434dd2a1ac3b","repo":"sipeed/picoclaw","slug":"invalid-wecom-qr-generate-url-w","errorCode":null,"errorMessage":"invalid WeCom QR generate URL: %w","messagePattern":"invalid WeCom QR generate URL: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/picoclaw/internal/auth/wecom.go","lineNumber":350,"sourceCode":"\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)\n\tquery.Set(\"plat\", strconv.Itoa(platformCode))\n\tu.RawQuery = query.Encode()\n\n\treturn u.String(), nil\n}\n\nfunc buildWeComQRQueryURL(baseURL, scode string) (string, error) {\n\tu, err := url.Parse(baseURL)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"invalid WeCom QR query URL: %w\", err)\n\t}\n\n\tquery := u.Query()","sourceCodeStart":332,"sourceCodeEnd":368,"githubUrl":"https://github.com/sipeed/picoclaw/blob/49183d7e8daed0dba89ddbb6fcb60089401d9680/cmd/picoclaw/internal/auth/wecom.go#L332-L368","documentation":"url.Parse rejected opts.GenerateURL while constructing the QR generate request. Go's url.Parse almost never fails (it accepts most strings), so this indicates a severely malformed URL — control characters, a bad escape sequence, or an empty/blank base URL that a custom option or test injected instead of the wecomQRGenerateEndpoint default.","triggerScenarios":"Programmatically overriding wecomQRFlowOptions.GenerateURL with an unvalidated string containing control chars or bad percent-escapes; unit tests passing an empty or malformed URL; a config/env override introducing whitespace or quotes into the URL.","commonSituations":"Fork code or tests customizing the relay endpoints; copy-paste of a URL with a stray newline; URL built by string concatenation with an unencoded value.","solutions":["Print the GenerateURL value being used and eyeball it for newlines, quotes, or raw spaces","Use the library default (omit the override) unless you truly need a custom relay","Percent-encode any dynamic values instead of concatenating raw strings","In tests, use httptest.Server URLs, which always parse"],"exampleFix":"// before\ngenerateURL, err := buildWeComQRGenerateURL(opts.GenerateURL, opts.SourceID, wecomPlatformCode())\n\n// after: fail fast on a bad override before entering the flow\nif _, err := url.Parse(opts.GenerateURL); err != nil {\n\treturn fmt.Errorf(\"invalid GenerateURL configured: %q: %w\", opts.GenerateURL, err)\n}","handlingStrategy":"validation","validationCode":"if _, err := url.Parse(opts.GenerateURL); err != nil {\n\treturn fmt.Errorf(\"GenerateURL %q is not a valid URL: %w\", opts.GenerateURL, err)\n}","typeGuard":"func isInvalidURL(err error) bool {\n\tvar uerr *url.Error\n\treturn errors.As(err, &uerr) || strings.Contains(err.Error(), \"invalid WeCom QR\")\n}","tryCatchPattern":null,"preventionTips":["Validate all relay URLs once at option-construction time","Never build URLs by concatenating unencoded values; use url.Values"],"tags":["go","wecom","url","validation","config"],"backgroundTag":null,"analyzedSha":"49183d7e8daed0dba89ddbb6fcb60089401d9680","analyzedAt":"2026-08-15T21:55:41.315Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}