{"record":{"id":"d65a0cb30e5ba662","repo":"fish2018/pansou","slug":"s-w-d65a0c","errorCode":null,"errorMessage":"[%s] 创建详情页请求失败: %w","messagePattern":"\\[(.+?)\\] 创建详情页请求失败: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/lou1/lou1.go","lineNumber":263,"sourceCode":"type lou1SearchHit struct {\n\tSubject   string `json:\"subject\"`\n\tThreadURL string `json:\"thread_url\"`\n}\n\ntype detailResult struct {\n\tlinks       []model.Link\n\tdatetime    time.Time\n\ttags        []string\n\tdescription string\n}\n\nfunc (p *Lou1Plugin) fetchDetail(client *http.Client, detailURL string) (detailResult, error) {\n\tctx, cancel := context.WithTimeout(context.Background(), detailTimeout)\n\tdefer cancel()\n\n\treq, err := http.NewRequestWithContext(ctx, http.MethodGet, detailURL, nil)\n\tif err != nil {\n\t\treturn detailResult{}, fmt.Errorf(\"[%s] 创建详情页请求失败: %w\", p.Name(), err)\n\t}\n\tsetHTMLHeaders(req, baseURL)\n\n\tresp, err := p.doRequestWithRetry(req, client, maxRequestRetries)\n\tif err != nil {\n\t\treturn detailResult{}, err\n\t}\n\tdefer resp.Body.Close()\n\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn detailResult{}, fmt.Errorf(\"[%s] 详情页返回状态码: %d\", p.Name(), resp.StatusCode)\n\t}\n\n\tdoc, err := goquery.NewDocumentFromReader(resp.Body)\n\tif err != nil {\n\t\treturn detailResult{}, fmt.Errorf(\"[%s] 解析详情页失败: %w\", p.Name(), err)\n\t}\n","sourceCodeStart":245,"sourceCodeEnd":281,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/lou1/lou1.go#L245-L281","documentation":"Lou1Plugin.fetchDetail builds a GET http.Request via http.NewRequestWithContext for a detail page URL; this error wraps any failure from that constructor. NewRequestWithContext only fails when the HTTP method is invalid, the URL cannot be parsed, or the URL scheme is unsupported (http/https only). In this plugin the method is a constant GET, so in practice the URL string itself is malformed.","triggerScenarios":"detailURL is not a parseable absolute URL (empty string, missing scheme, contains spaces or control characters), or has a scheme other than http/https. The method is always http.MethodGet here so method validation never fails.","commonSituations":"A search hit returns a relative or empty thread_url that is joined into detailURL incorrectly; upstream changed its thread_url format; a redirect target with an unusual scheme is followed into the detail fetch.","solutions":["Log the wrapped %w error and the exact detailURL value to see the url.Parse failure reason","Validate the detail URL before calling fetchDetail: require an absolute http(s) URL (url.ParseRequestURI + scheme check)","Fix URL construction so thread_url is resolved against baseURL with net/url ResolveReference, and skip hits with empty/invalid URLs"],"exampleFix":"// before\nreq, err := http.NewRequestWithContext(ctx, http.MethodGet, detailURL, nil)\n// after\nu, perr := url.Parse(detailURL)\nif perr != nil || (u.Scheme != \"http\" && u.Scheme != \"https\") {\n    return detailResult{}, fmt.Errorf(\"invalid detail url %q\", detailURL)\n}\nreq, err := http.NewRequestWithContext(ctx, http.MethodGet, u.String(), nil)","handlingStrategy":"validation","validationCode":"u, err := url.Parse(detailURL)\nif err != nil || (u.Scheme != \"http\" && u.Scheme != \"https\") || u.Host == \"\" {\n    // skip this result instead of calling fetchDetail\n    return skip\n}","typeGuard":"func isValidHTTPURL(raw string) bool {\n    u, err := url.Parse(raw)\n    return err == nil && (u.Scheme == \"http\" || u.Scheme == \"https\") && u.Host != \"\"\n}","tryCatchPattern":"if err != nil {\n    var uerr *url.Error\n    if errors.As(err, &uerr) {\n        log.Printf(\"bad detail url %q: %v\", detailURL, uerr)\n    }\n    return detailResult{}, fmt.Errorf(\"...\")\n}","preventionTips":["Resolve relative thread_url values against baseURL with url.Parse and ResolveReference before fetching","Skip search hits whose URL is empty or fails validation rather than passing them downstream","Add a unit test covering malformed thread_url inputs"],"tags":["http","url","request-construction"],"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"}