fish2018/pansou · warning

[ ] 429限流,

Error message

[%s] 429限流,%s

What it means

doRequestWithRateLimitRetry returns '[javdb] 429限流,%s' (429 rate limited) when the server responds 429 and the plugin either has MaxRetryOnRateLimit == 0 (no retries allowed) or has already exhausted the allowed retry attempts. It also sets the plugin's atomic rateLimited flag so the caller knows the source is throttled.

Solutions

  1. Increase MaxRetryOnRateLimit or remove a 0 setting that disables retries
  2. Add per-request delay/rate limiting between detail-page fetches
  3. Respect any Retry-After header from the 429 response before retrying
  4. Back off globally when the rateLimited flag is set (skip javdb for a cooldown period)
  5. Reduce concurrency/parallel requests to javdb

Example fix

// before
for _, link := range links {
    fetchDetail(link)
}
// after
for _, link := range links {
    fetchDetail(link)
    time.Sleep(requestInterval)
}
Defensive patterns

Strategy: fallback

Validate before calling

// Go: throttle before issuing detail requests
if atomic.LoadInt32(&p.rateLimited) == 1 {
    return nil, errors.New("javdb cooling down after 429")
}
<-time.Tick(requestInterval)

Type guard

func isRateLimited(err error) bool {
    return err != nil && strings.Contains(err.Error(), "429限流")
}

Try / catch

magnets, err := p.fetchDetailPageMagnetLinks(url, client)
if isRateLimited(err) {
    time.Sleep(cooldownPeriod)
    magnets, err = p.fetchDetailPageMagnetLinks(url, client)
}

Prevention

When it happens

Trigger: fetchDetailPageMagnetLinks (or another caller) issues requests fast enough that javdb answers 429; either retries are disabled by configuration or attempt >= MaxRetryOnRateLimit is reached while still receiving 429.

Common situations: Scraping many detail pages in a tight loop without delays; shared IP (VPN/datacenter) already throttled; MaxRetryOnRateLimit configured to 0; bursty concurrent searches from multiple users.

Related errors


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

Appendix: source

Thrown at plugin/javdb/javdb.go:315

			continue
		}
		
		// 如果不是429,直接返回(无论成功还是其他错误)
		if resp.StatusCode != 429 {
			return resp, nil
		}
		
		// 遇到429
		atomic.AddInt32(&p.rateLimitCount, 1)
		if p.debugMode {
			log.Printf("[JAVDB] 遇到429限流,尝试 %d/%d", attempt+1, MaxRetryOnRateLimit+1)
		}
		
		// 如果不允许重试或已达到最大重试次数
		if MaxRetryOnRateLimit == 0 || attempt >= MaxRetryOnRateLimit {
			atomic.StoreInt32(&p.rateLimited, 1)
			resp.Body.Close()
			return nil, fmt.Errorf("[%s] 429限流,%s", p.Name(), 
				func() string {
					if MaxRetryOnRateLimit == 0 {
						return "不重试"
					}
					return fmt.Sprintf("重试%d次后仍然限流", MaxRetryOnRateLimit)
				}())
		}
		
		resp.Body.Close()
		lastErr = fmt.Errorf("429 Too Many Requests")
	}
	
	return nil, lastErr
}

// parseSearchResults 解析搜索结果HTML
func (p *JavdbPlugin) parseSearchResults(doc *goquery.Document) ([]model.SearchResult, error) {
	var results []model.SearchResult

View on GitHub (pinned to beaa561337)