{"record":{"id":"fda17fd55745a73d","repo":"fish2018/pansou","slug":"s-w-fda17f","errorCode":null,"errorMessage":"[%s] 执行搜索失败: %w","messagePattern":"\\[(.+?)\\] 执行搜索失败: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/javdb/javdb.go","lineNumber":117,"sourceCode":"// SearchWithResult 执行搜索并返回包含IsFinal标记的结果\nfunc (p *JavdbPlugin) SearchWithResult(keyword string, ext map[string]interface{}) (model.PluginSearchResult, error) {\n\treturn p.AsyncSearchWithResult(keyword, p.searchImpl, p.MainCacheKey, ext)\n}\n\n// searchImpl 搜索实现\nfunc (p *JavdbPlugin) searchImpl(client *http.Client, keyword string, ext map[string]interface{}) ([]model.SearchResult, error) {\n\tif p.debugMode {\n\t\tlog.Printf(\"[JAVDB] 开始搜索: %s\", keyword)\n\t}\n\n\tif p.debugMode {\n\t\tlog.Printf(\"[JAVDB] 开始搜索，客户端超时: %v\", client.Timeout)\n\t}\n\n\t// 第一步：执行搜索获取结果列表\n\tsearchResults, err, isRateLimited := p.executeSearchWithRateLimit(client, keyword)\n\tif err != nil && !isRateLimited {\n\t\treturn nil, fmt.Errorf(\"[%s] 执行搜索失败: %w\", p.Name(), err)\n\t}\n\n\tif p.debugMode {\n\t\tif isRateLimited {\n\t\t\tlog.Printf(\"[JAVDB] ⚡ 遇到429限流，但继续处理已获取的 %d 个结果\", len(searchResults))\n\t\t} else {\n\t\t\tlog.Printf(\"[JAVDB] 搜索获取到 %d 个结果\", len(searchResults))\n\t\t}\n\t}\n\n\t// 如果没有搜索结果，直接返回\n\tif len(searchResults) == 0 {\n\t\tif p.debugMode {\n\t\t\tlog.Printf(\"[JAVDB] 无搜索结果，直接返回\")\n\t\t}\n\t\treturn []model.SearchResult{}, nil\n\t}\n","sourceCodeStart":99,"sourceCodeEnd":135,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/javdb/javdb.go#L99-L135","documentation":"searchImpl in the javdb plugin wraps any non-rate-limited failure from executeSearchWithRateLimit as '[javdb] 执行搜索失败: %w' (search execution failed). It is the top-level error aggregator for the search step; rate-limited runs (isRateLimited=true) are deliberately not wrapped because partial results are still processed.","triggerScenarios":"executeSearchWithRateLimit returns an error with isRateLimited=false — e.g. request creation failure, client.Do transport error, non-200 status, body read failure, or HTML parse failure.","commonSituations":"javdb blocks or changes its endpoint; network egress blocked in the container; HTTP client timeout too short; site returns 5xx or a bot-block page; goquery fails on an unexpected response.","solutions":["Unwrap the %w cause to find which inner step failed","Curl the javdb search URL with the same headers to check reachability/blocking","Verify the search URL and User-Agent still match the current site behavior","Increase the client timeout if failures correlate with slow responses","Treat this error in callers as 'source temporarily unavailable' and fall back to other plugins"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Go: check source reachability before invoking search\nresp, err := http.Head(\"https://javdb.com\")\nif err != nil || resp.StatusCode >= 400 {\n    log.Printf(\"javdb unreachable, skipping\")\n}","typeGuard":"func isSearchExecFailure(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"执行搜索失败\")\n}","tryCatchPattern":"results, err := p.searchImpl(client, keyword)\nif err != nil {\n    var inner error = errors.Unwrap(err)\n    log.Printf(\"javdb search failed (cause=%v): %v\", inner, err)\n    return nil, err\n}","preventionTips":["Always unwrap the %w cause before diagnosing","Curl the endpoint with the same headers when errors appear","Keep User-Agent and endpoint URL in sync with site changes","Treat this as a transient source failure and fall back to other plugins"],"tags":["http","scraping","go","plugin"],"backgroundTag":"api-request-failed","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"}