fish2018/pansou · error
[susu] 帖子 的下载按钮均未返回有效链接
Error message
[susu] 帖子 %s 的下载按钮均未返回有效链接
What it means
getLinks throws this when the post had download buttons (totalButtons > 0) but every button's link-resolution attempt either failed or produced duplicates filtered out by the seen-dedup, leaving zero valid links. All per-button fetches errored, timed out, or returned unusable URLs (e.g. all empty/dead).
Solutions
- Check the per-button error paths' logs to see whether failures are network, HTTP status, or parse errors.
- Verify the download hosts directly (open one button's URL in a browser) — links may simply be dead.
- Confirm the per-button HTML/JSON extraction still matches the current site markup.
- Retry later if the download host is temporarily down; consider increasing retries/timeouts for individual link fetches.
- If all links dedupe to nothing, inspect the key used in seen — an over-aggressive dedup key could filter valid links.
Example fix
null
Defensive patterns
Strategy: fallback
Try / catch
links, err := p.getLinks(postID)
if err != nil && strings.Contains(err.Error(), "均未返回有效链接") {
// per-button resolvers all failed; try alternate source or report dead links
return alternateResolver.Resolve(postID)
} Prevention
- Monitor the download hosts independently of the button-list API
- Log per-button failures to distinguish dead links from extraction bugs
- Keep per-button HTML extraction updated with site changes
- Provide a secondary resolver or cached links as fallback
- Review the dedup key so valid links aren't filtered as duplicates
When it happens
Trigger: After consuming linkChan and deduplicating via seen[key], len(links) == 0 — every download button's resolver failed (network errors, per-button timeouts, HTTP errors) or every candidate link was filtered as invalid/duplicate.
Common situations: The download host(s) being down or geo-blocked while the button-list API still works; expired/dead file links on an old post; per-button resolvers broken after a site layout change; MaxConcurrency/semaphore starving under timeouts.
Understand the failure class
Background: EmptyResultError / "no results found": when an API or scraper succeeds but returns zero rows — this error's family across 9 libraries.
Related errors
AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07).
Data as JSON: /api/errors/5e3cbc164ada8f26.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/susu/susu.go:418
// 等待所有goroutine完成
go func() {
wgLinks.Wait()
close(linkChan)
}()
// 收集结果
links := make([]model.Link, 0, totalButtons)
seen := make(map[string]struct{}, totalButtons)
for link := range linkChan {
key := link.Type + "\x00" + link.URL + "\x00" + link.Password
if _, exists := seen[key]; exists {
continue
}
seen[key] = struct{}{}
links = append(links, link)
}
if len(links) == 0 {
return nil, fmt.Errorf("[susu] 帖子 %s 的下载按钮均未返回有效链接", postID)
}
// 缓存结果
buttonListCache.Store(postID, links)
return links, nil
}
// getButtonDetail 获取按钮详情
func (p *SusuAsyncPlugin) getButtonDetail(client *http.Client, postID string, index, i int) (model.Link, error) {
// 生成缓存键
cacheKey := fmt.Sprintf("%s:%d:%d", postID, index, i)
// 检查缓存
if cachedLink, ok := buttonDetailCache.Load(cacheKey); ok {
return cachedLink.(model.Link), nil
}
View on GitHub (pinned to beaa561337)