fish2018/pansou · error
[susu] 创建按钮列表请求失败
Error message
[susu] 创建按钮列表请求失败: %w
What it means
getLinks throws this when http.NewRequestWithContext fails to construct the POST request to ButtonListURL with the encoded form body. This is a client-side request construction error: a malformed URL, an invalid method, or an unreadable body — it never leaves the process. NewRequest only errors on invalid URL parsing, unsupported method characters, or a broken reader.
Solutions
- Inspect ButtonListURL — validate it parses with url.Parse and is absolute (scheme + host).
- Check for accidental whitespace/control characters in the URL string or its format arguments (postID).
- Verify postID doesn't contain characters that break the Sprintf'd referer/URL construction.
- Add a startup-time validation of ButtonListURL so failures surface at config load, not per request.
Example fix
// before
req, err := http.NewRequestWithContext(ctx, http.MethodPost, ButtonListURL, strings.NewReader(form.Encode()))
// after: validate the URL first
if u, uerr := url.Parse(ButtonListURL); uerr != nil || u.Scheme == "" || u.Host == "" {
return nil, fmt.Errorf("[susu] invalid ButtonListURL %q: %w", ButtonListURL, uerr)
}
req, err := http.NewRequestWithContext(ctx, http.MethodPost, ButtonListURL, strings.NewReader(form.Encode())) Defensive patterns
Strategy: validation
Validate before calling
u, err := url.Parse(ButtonListURL)
if err != nil || u.Scheme == "" || u.Host == "" {
// refuse to call getLinks with a malformed endpoint
} Try / catch
links, err := p.getLinks(postID)
if err != nil && strings.Contains(err.Error(), "创建按钮列表请求失败") {
// configuration bug, not transient — do not retry
log.Printf("invalid ButtonListURL configuration: %v", err)
} Prevention
- Validate ButtonListURL at startup with url.Parse
- Never build URLs by raw string concatenation
- Keep postID sanitized/URL-encoded
When it happens
Trigger: getLinks builds the button-list request and ButtonListURL is malformed/unparseable (invalid characters, bad scheme), or strings.NewReader(form.Encode()) yields a nil/broken body — NewRequestWithContext returns err immediately.
Common situations: ButtonListURL constant edited to an invalid URL; config-supplied URL with spaces or unencoded characters; empty/nil base URL combined via a bad join producing '://...'.
Understand the failure class
Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.
Related errors
AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07).
Data as JSON: /api/errors/f3716508a6106dcf.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/susu/susu.go:349
}
// getLinks 获取网盘链接
func (p *SusuAsyncPlugin) getLinks(client *http.Client, postID string) ([]model.Link, error) {
// 检查缓存
if cachedLinks, ok := buttonListCache.Load(postID); ok {
return cachedLinks.([]model.Link), nil
}
form := url.Values{
"post_id": {postID},
"guest": {""},
}
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
defer cancel()
req, err := http.NewRequestWithContext(ctx, http.MethodPost, ButtonListURL, strings.NewReader(form.Encode()))
if err != nil {
return nil, fmt.Errorf("[susu] 创建按钮列表请求失败: %w", err)
}
setAPIHeaders(req, fmt.Sprintf("%s/%s.html", BaseURL, postID))
resp, err := p.doRequestWithRetry(client, req, MaxRetries)
if err != nil {
return nil, fmt.Errorf("[susu] 获取按钮列表失败: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("[susu] 按钮列表请求返回状态码: %d", resp.StatusCode)
}
respBody, err := io.ReadAll(io.LimitReader(resp.Body, 2<<20))
if err != nil {
return nil, fmt.Errorf("[susu] 读取按钮列表失败: %w", err)
}
var groups []downloadGroupView on GitHub (pinned to beaa561337)