{"record":{"id":"f3716508a6106dcf","repo":"fish2018/pansou","slug":"susu-w","errorCode":null,"errorMessage":"[susu] 创建按钮列表请求失败: %w","messagePattern":"\\[susu\\] 创建按钮列表请求失败: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/susu/susu.go","lineNumber":349,"sourceCode":"}\n\n// getLinks 获取网盘链接\nfunc (p *SusuAsyncPlugin) getLinks(client *http.Client, postID string) ([]model.Link, error) {\n\t// 检查缓存\n\tif cachedLinks, ok := buttonListCache.Load(postID); ok {\n\t\treturn cachedLinks.([]model.Link), nil\n\t}\n\n\tform := url.Values{\n\t\t\"post_id\": {postID},\n\t\t\"guest\":   {\"\"},\n\t}\n\tctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)\n\tdefer cancel()\n\n\treq, err := http.NewRequestWithContext(ctx, http.MethodPost, ButtonListURL, strings.NewReader(form.Encode()))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[susu] 创建按钮列表请求失败: %w\", err)\n\t}\n\tsetAPIHeaders(req, fmt.Sprintf(\"%s/%s.html\", BaseURL, postID))\n\n\tresp, err := p.doRequestWithRetry(client, req, MaxRetries)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[susu] 获取按钮列表失败: %w\", err)\n\t}\n\tdefer resp.Body.Close()\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn nil, fmt.Errorf(\"[susu] 按钮列表请求返回状态码: %d\", resp.StatusCode)\n\t}\n\n\trespBody, err := io.ReadAll(io.LimitReader(resp.Body, 2<<20))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[susu] 读取按钮列表失败: %w\", err)\n\t}\n\n\tvar groups []downloadGroup","sourceCodeStart":331,"sourceCodeEnd":367,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/susu/susu.go#L331-L367","documentation":"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.","triggerScenarios":"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.","commonSituations":"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 '://...'.","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."],"exampleFix":"// before\nreq, err := http.NewRequestWithContext(ctx, http.MethodPost, ButtonListURL, strings.NewReader(form.Encode()))\n// after: validate the URL first\nif u, uerr := url.Parse(ButtonListURL); uerr != nil || u.Scheme == \"\" || u.Host == \"\" {\n    return nil, fmt.Errorf(\"[susu] invalid ButtonListURL %q: %w\", ButtonListURL, uerr)\n}\nreq, err := http.NewRequestWithContext(ctx, http.MethodPost, ButtonListURL, strings.NewReader(form.Encode()))","handlingStrategy":"validation","validationCode":"u, err := url.Parse(ButtonListURL)\nif err != nil || u.Scheme == \"\" || u.Host == \"\" {\n    // refuse to call getLinks with a malformed endpoint\n}","typeGuard":null,"tryCatchPattern":"links, err := p.getLinks(postID)\nif err != nil && strings.Contains(err.Error(), \"创建按钮列表请求失败\") {\n    // configuration bug, not transient — do not retry\n    log.Printf(\"invalid ButtonListURL configuration: %v\", err)\n}","preventionTips":["Validate ButtonListURL at startup with url.Parse","Never build URLs by raw string concatenation","Keep postID sanitized/URL-encoded"],"tags":["http-request","url-construction","client-side"],"backgroundTag":"invalid-url-format","analyzedSha":"beaa56133755a548ebc51b090b3816e2ae044aa6","analyzedAt":"2026-09-07T00:31:18.025Z","contentChangedAt":"2026-09-07T00:31:18.025Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}