fish2018/pansou · error

cloudscraper not initialized

Error message

cloudscraper not initialized

What it means

PanzunPlugin.searchImpl returns this error when the plugin's cloudscraper client (p.scraper) is still nil when a search is executed. The scraper must be created during plugin construction (NewPanzunPlugin) before AsyncSearchWithResult dispatches searchImpl in a worker. A nil scraper means every HTTP request would panic, so the code fails fast with this sentinel error.

Solutions

  1. Instantiate the plugin only through its constructor so p.scraper is set before search
  2. Add a lazy-init or nil check that creates the scraper on first use if it is nil
  3. Verify the scraper construction code isn't gated behind a config/env condition that is false in this environment

Example fix

// before
p := &panzun.PanzunPlugin{}
results, err := p.Search(keyword, nil) // error: cloudscraper not initialized
// after
p := panzun.NewPanzunPlugin()
results, err := p.Search(keyword, nil)
Defensive patterns

Strategy: validation

Validate before calling

if p == nil || p.scraper == nil {
    return fmt.Errorf("plugin not initialized: scraper is nil")
}
_ = p.Search(keyword, ext)

Type guard

func (p *PanzunPlugin) ready() bool { return p != nil && p.scraper != nil }

Try / catch

results, err := plugin.Search(keyword, ext)
if err != nil {
    if strings.Contains(err.Error(), "cloudscraper not initialized") {
        plugin = panzun.NewPanzunPlugin() // rebuild and retry once
        results, err = plugin.Search(keyword, ext)
    }
}

Prevention

When it happens

Trigger: Calling Search/SearchWithResult on a PanzunPlugin instance constructed without initializing p.scraper — e.g. a zero-value PanzunPlugin{} created by hand instead of via the plugin's constructor, or scraper initialization skipped/failing silently before registration.

Common situations: Plugin registered but its constructor bypassed (manual instantiation, reflection-based loading, config-driven creation that doesn't call init code); refactor moved scraper creation out of the constructor; tests instantiating the struct directly.

Related errors


AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07). Data as JSON: /api/errors/a6535d909f1300bc. Report an issue: GitHub.

Appendix: source

Thrown at plugin/panzun/panzun.go:110

		},
	}
}

func (p *PanzunPlugin) 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
}

func (p *PanzunPlugin) SearchWithResult(keyword string, ext map[string]interface{}) (model.PluginSearchResult, error) {
	return p.AsyncSearchWithResult(keyword, p.searchImpl, p.MainCacheKey, ext)
}

func (p *PanzunPlugin) searchImpl(client *http.Client, keyword string, ext map[string]interface{}) ([]model.SearchResult, error) {
	if p.scraper == nil {
		return nil, fmt.Errorf("cloudscraper not initialized")
	}

	var allResults []model.SearchResult
	seenIDs := make(map[string]bool)

	for page := 1; page <= maxPages; page++ {
		offset := (page - 1) * pageSize
		searchURL := fmt.Sprintf("%s/discussions?filter[q]=%s&page[offset]=%d", apiBase, url.QueryEscape(keyword), offset)

		resp, err := p.scraper.Get(searchURL)
		if err != nil {
			if len(allResults) > 0 {
				fmt.Printf("[%s] Warning: failed to fetch page %d: %v\n", p.Name(), page, err)
				break
			}
			return nil, fmt.Errorf("[%s] search request failed on page %d: %w", p.Name(), page, err)
		}

View on GitHub (pinned to beaa561337)