fish2018/pansou · error
cloudscraper not initialized
Error message
cloudscraper not initialized
What it means
The Discourse async plugin's searchImpl returns this sentinel error when p.scraper is nil, i.e. the cloudscraper client required to make Cloudflare-resilient requests was never initialized. Unlike other plugins this message is a plain English string without the plugin name prefix.
Solutions
- Check startup logs for the cloudscraper initialization failure and fix it.
- Ensure the plugin's initialization that assigns p.scraper always runs before searching.
- Fail fast at registration time if the scraper cannot be created.
- If a plain http.Client suffices for non-Cloudflare instances, add a fallback path instead of erroring.
Example fix
// before
p := &DiscourseAsyncPlugin{}
results, err := p.Search(keyword) // error: cloudscraper not initialized
// after
p := NewDiscourseAsyncPlugin()
if err := p.Init(cfg); err != nil { log.Fatalf("init: %v", err) }
results, err := p.Search(keyword) Defensive patterns
Strategy: validation
Validate before calling
if p.scraper == nil {
return errors.New("discourse plugin not initialized: cloudscraper is nil")
}
// safe to search Try / catch
if err != nil {
if err.Error() == "cloudscraper not initialized" {
return fmt.Errorf("run plugin Init before searching: %w", err)
}
return err
} Prevention
- Initialize the plugin via its constructor/Init and check errors at startup.
- Add fail-fast assertions that scraper is non-nil at registration.
- Avoid raw struct-literal construction in production code and tests.
When it happens
Trigger: searchImpl is called (via the async search path) before or without a successful scraper initialization: Init/constructor failure, plugin registered but never configured, or instantiation in tests bypassing setup.
Common situations: cloudscraper init error swallowed at startup; plugin config missing required options for scraper creation; unit tests constructing the struct literal without running setup.
Related errors
- [ ] Cloudflare 请求客户端未初始化
- [ ] 触发 Cloudflare Managed Challenge (HTTP )
- [ ] search request failed on page
- detail request failed
- unexpected status code
AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07).
Data as JSON: /api/errors/11285b234858988a.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/discourse/discourse.go:166
func (p *DiscourseAsyncPlugin) Search(keyword string, ext map[string]interface{}) ([]model.SearchResult, error) {
result, err := p.SearchWithResult(keyword, ext)
if err != nil {
return nil, err
}
return result.Results, nil
}
// SearchWithResult 执行搜索并返回包含IsFinal标记的结果
func (p *DiscourseAsyncPlugin) SearchWithResult(keyword string, ext map[string]interface{}) (model.PluginSearchResult, error) {
// 使用BaseAsyncPlugin的异步搜索能力
return p.AsyncSearchWithResult(keyword, p.searchImpl, p.MainCacheKey, ext)
}
// searchImpl 实现具体的搜索逻辑
func (p *DiscourseAsyncPlugin) searchImpl(client *http.Client, keyword string, ext map[string]interface{}) ([]model.SearchResult, error) {
// 检查 cloudscraper 是否初始化成功
if p.scraper == nil {
return nil, fmt.Errorf("cloudscraper not initialized")
}
// 提取 max_pages 参数(最多获取多少页)
maxPages := defaultMaxPages
if maxPagesVal, ok := ext["max_pages"]; ok {
if maxPagesInt, ok := maxPagesVal.(int); ok {
maxPages = maxPagesInt
} else if maxPagesFloat, ok := maxPagesVal.(float64); ok {
maxPages = int(maxPagesFloat)
}
}
// 限制最大页数
if maxPages > maxAllowedPages {
maxPages = maxAllowedPages
}
if maxPages < 1 {
maxPages = 1View on GitHub (pinned to beaa561337)