{"record":{"id":"43fc027bd139fd58","repo":"fish2018/pansou","slug":"s-cloudflare","errorCode":null,"errorMessage":"[%s] Cloudflare 请求客户端未初始化","messagePattern":"\\[(.+?)\\] Cloudflare 请求客户端未初始化","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/diduan/diduan.go","lineNumber":130,"sourceCode":"\n// Search 搜索接口\nfunc (p *DiduanPlugin) Search(keyword string, ext map[string]interface{}) ([]model.SearchResult, error) {\n\tresult, err := p.SearchWithResult(keyword, ext)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn result.Results, nil\n}\n\n// SearchWithResult 使用 BaseAsyncPlugin 的缓存和后台刷新能力。\nfunc (p *DiduanPlugin) 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 *DiduanPlugin) searchImpl(client *http.Client, keyword string, ext map[string]interface{}) ([]model.SearchResult, error) {\n\tif p.scraper == nil {\n\t\treturn nil, fmt.Errorf(\"[%s] Cloudflare 请求客户端未初始化\", p.Name())\n\t}\n\tif p.debugMode {\n\t\tlog.Printf(\"[DIDUAN] 开始搜索: %s\", keyword)\n\t}\n\n\t// 第一步：执行搜索获取结果列表\n\tsearchResults, err := p.executeSearch(keyword)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] 执行搜索失败: %w\", p.Name(), err)\n\t}\n\n\tif p.debugMode {\n\t\tlog.Printf(\"[DIDUAN] 搜索获取到 %d 个结果\", len(searchResults))\n\t}\n\n\t// 第二步：并发获取详情页链接\n\tfinalResults := p.fetchDetailLinks(searchResults, keyword)\n","sourceCodeStart":112,"sourceCodeEnd":148,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/diduan/diduan.go#L112-L148","documentation":"The Diduan plugin relies on a cloudscraper client (p.scraper) initialized during plugin setup to bypass Cloudflare. searchImpl returns this error immediately when p.scraper is nil, meaning the Cloudflare-capable client was never constructed successfully.","triggerScenarios":"p.searchImpl is invoked (via AsyncSearchWithResult) but plugin initialization failed or was skipped, leaving p.scraper nil — e.g. the cloudscraper constructor returned an error that was ignored or logged only.","commonSituations":"Missing dependencies or options for initializing the scraper at startup; plugin constructed directly in tests without calling the init routine; an earlier init failure (bad proxy config, missing browser fingerprint data) left the scraper unset.","solutions":["Check plugin startup logs for the cloudscraper initialization error and fix the root cause.","Ensure the plugin's Init/constructor that creates p.scraper runs before any search is issued.","Validate scraper-related configuration (proxy, browser emulation options) is present and valid.","Add a startup health check that fails fast if p.scraper is nil instead of failing at search time."],"exampleFix":"// before\np := &DiduanPlugin{}\nresults, err := p.Search(keyword) // fails: scraper nil\n// after\np := NewDiduanPlugin()\nif err := p.Init(cfg); err != nil { log.Fatalf(\"init: %v\", err) }\nresults, err := p.Search(keyword)","handlingStrategy":"validation","validationCode":"if p.scraper == nil {\n    return errors.New(\"diduan plugin not initialized: scraper is nil\")\n}\n// safe to search","typeGuard":null,"tryCatchPattern":"if err != nil {\n    if strings.Contains(err.Error(), \"未初始化\") {\n        return fmt.Errorf(\"re-init plugin before searching: %w\", err)\n    }\n    return err\n}","preventionTips":["Always run plugin Init and check its error before issuing searches.","Add a startup assertion that required clients (scraper) are non-nil.","Construct plugins through factory functions, not raw struct literals."],"tags":["cloudflare","initialization","nil-check","plugin","go"],"backgroundTag":"module-init-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"}