{"record":{"id":"3c3780cd0bf5d7e0","repo":"sipeed/picoclaw","slug":"invalid-wecom-qr-query-url-w","errorCode":null,"errorMessage":"invalid WeCom QR query URL: %w","messagePattern":"invalid WeCom QR query URL: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/picoclaw/internal/auth/wecom.go","lineNumber":365,"sourceCode":"func 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()\n\tquery.Set(\"scode\", scode)\n\tu.RawQuery = query.Encode()\n\n\treturn u.String(), nil\n}\n\nfunc buildWeComQRCodePageURL(baseURL, sourceID, scode string) (string, error) {\n\tu, err := url.Parse(baseURL)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"invalid WeCom QR page URL: %w\", err)\n\t}\n\n\tquery := u.Query()\n\tquery.Set(\"source\", sourceID)\n\tquery.Set(\"sourceID\", sourceID)","sourceCodeStart":347,"sourceCodeEnd":383,"githubUrl":"https://github.com/sipeed/picoclaw/blob/49183d7e8daed0dba89ddbb6fcb60089401d9680/cmd/picoclaw/internal/auth/wecom.go#L347-L383","documentation":"url.Parse rejected opts.QueryURL inside buildWeComQRQueryURL, which is called on every poll iteration. Same class as error 133 but for the status-query endpoint: the configured base URL is unparseable (control characters, invalid escapes), which in practice only happens with a custom/injected QueryURL rather than the wecomQRQueryEndpoint default.","triggerScenarios":"Custom wecomQRFlowOptions with a malformed QueryURL; tests stubbing the query endpoint with a bad string; env/config override introducing trailing garbage onto the URL.","commonSituations":"Pointing picoclaw at a self-hosted WeCom QR relay with a typo; string-built URLs with unencoded inserts; stale override surviving from an experiment.","solutions":["Validate the QueryURL override once before the flow starts (see validation example)","Use the default relay unless a custom one is required","Trim whitespace and remove quotes/newlines from any URL sourced from env/config","Log the offending value at configuration time so the failure is obvious"],"exampleFix":"// before\nqueryURL, err := buildWeComQRQueryURL(opts.QueryURL, scode)\n\n// after: preflight once in the caller\nif _, err := url.Parse(opts.QueryURL); err != nil {\n\treturn fmt.Errorf(\"invalid QueryURL %q: %w\", opts.QueryURL, err)\n}","handlingStrategy":"validation","validationCode":"if _, err := url.Parse(opts.QueryURL); err != nil {\n\treturn fmt.Errorf(\"QueryURL %q is not a valid URL: %w\", opts.QueryURL, err)\n}","typeGuard":"func isInvalidURL(err error) bool {\n\treturn err != nil && strings.Contains(err.Error(), \"invalid URL\")\n}","tryCatchPattern":null,"preventionTips":["Preflight endpoint URLs before entering a polling loop so failure is early and clear","Source custom URLs only from validated configuration"],"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"}