{"record":{"id":"9595b49271cb3b1a","repo":"fish2018/pansou","slug":"s-w-9595b4","errorCode":null,"errorMessage":"[%s] 创建请求失败: %w","messagePattern":"\\[(.+?)\\] 创建请求失败: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/kkv/kkv.go","lineNumber":123,"sourceCode":"\t\tif strings.Contains(lowerTitle, lowerKeyword) {\n\t\t\tdebugPrintf(\"✅ 标题匹配: %s\\n\", item.Title)\n\t\t\tfiltered = append(filtered, item)\n\t\t} else {\n\t\t\tdebugPrintf(\"❌ 标题不匹配，跳过: %s\\n\", item.Title)\n\t\t}\n\t}\n\t\n\treturn filtered\n}\n\nfunc (p *KKVPlugin) fetchSearchResults(searchURL string, client *http.Client) ([]searchItem, error) {\n\tdebugPrintf(\"🌐 请求搜索页面: %s\\n\", searchURL)\n\tctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)\n\tdefer cancel()\n\t\n\treq, err := http.NewRequestWithContext(ctx, \"GET\", searchURL, nil)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] 创建请求失败: %w\", p.Name(), err)\n\t}\n\t\n\tp.setHeaders(req, baseURL)\n\t\n\tresp, err := p.doRequestWithRetry(req, client)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] 搜索请求失败: %w\", p.Name(), err)\n\t}\n\tdefer resp.Body.Close()\n\t\n\tdebugPrintf(\"📡 HTTP状态码: %d\\n\", resp.StatusCode)\n\t\n\tif resp.StatusCode != 200 {\n\t\treturn nil, fmt.Errorf(\"[%s] 请求返回状态码: %d\", p.Name(), resp.StatusCode)\n\t}\n\t\n\tdoc, err := goquery.NewDocumentFromReader(resp.Body)\n\tif err != nil {","sourceCodeStart":105,"sourceCodeEnd":141,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/kkv/kkv.go#L105-L141","documentation":"The kkv plugin's fetchSearchResults wraps an error from http.NewRequestWithContext when building the search GET request. This means the request object itself could not be constructed — almost always because the search URL is unparseable (invalid scheme, control characters, bad host). It is a local client-side error, not a server problem.","triggerScenarios":"http.NewRequestWithContext returns non-nil err while constructing the GET for searchURL, e.g. a malformed or empty base URL configured for the kkv source, an unescaped keyword containing spaces/control chars interpolated into the URL, or an invalid context.","commonSituations":"Misconfigured kkv base URL (typo like 'htp://' or missing scheme), keyword not URL-encoded before being put into the search URL format string, stale base-site URL after the site changed domains.","solutions":["Validate/URL-encode the search keyword (url.QueryEscape) before it is inserted into the search URL","Check the configured kkv base URL has scheme http(s):// and a valid host; fix the plugin config or site list","Print the failing searchURL alongside the wrapped error to see exactly what string NewRequest rejected","Update the plugin's site base URL if the source moved domains"],"exampleFix":"// before\nsearchURL := fmt.Sprintf(\"%s/search/%s/page/1\", baseURL, keyword)\n// after\nsearchURL := fmt.Sprintf(\"%s/search/%s/page/1\", strings.TrimRight(baseURL, \"/\"), url.QueryEscape(keyword))","handlingStrategy":"validation","validationCode":"u, err := url.Parse(searchURL)\nif err != nil || u.Scheme == \"\" || u.Host == \"\" {\n    // do not call the plugin with this URL/keyword\n}","typeGuard":"func isValidURL(s string) bool {\n    u, err := url.Parse(s)\n    return err == nil && (u.Scheme == \"http\" || u.Scheme == \"https\") && u.Host != \"\"\n}","tryCatchPattern":"results, err := plugin.Search(ctx, kw)\nif err != nil {\n    var urlErr *url.Error\n    if errors.As(err, &urlErr) {\n        log.Printf(\"bad request URL %q: %v\", urlErr.URL, urlErr.Err)\n    }\n    return nil\n}","preventionTips":["Always url.QueryEscape user-supplied keywords before interpolation","Validate configured base URLs at startup (scheme + host present)","Trim whitespace from any URL that was scraped or read from config","Log the full failing URL, not just the error text"],"tags":["network","http","url","scraping"],"backgroundTag":"invalid-url","analyzedSha":"beaa56133755a548ebc51b090b3816e2ae044aa6","analyzedAt":"2026-09-07T00:31:18.025Z","contentChangedAt":"2026-09-07T00:31:18.025Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}