{"record":{"id":"0b0a689457364705","repo":"AlistGo/alist","slug":"http-request-s-failure-status-d-response-s","errorCode":null,"errorMessage":"http request [%s] failure,status: %d response:%s","messagePattern":"http request \\[(.+?)\\] failure,status: (.+?) response:(.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/net/serve.go","lineNumber":259,"sourceCode":"\t// TODO clean header with blocklist or passlist\n\tres.Header.Del(\"set-cookie\")\n\tvar reader io.Reader\n\tif res.StatusCode >= 400 {\n\t\t// 根据 Content-Encoding 判断 Body 是否压缩\n\t\tswitch res.Header.Get(\"Content-Encoding\") {\n\t\tcase \"gzip\":\n\t\t\t// 使用gzip.NewReader解压缩\n\t\t\treader, _ = gzip.NewReader(res.Body)\n\t\t\tdefer reader.(*gzip.Reader).Close()\n\t\tdefault:\n\t\t\t// 没有Content-Encoding，直接读取\n\t\t\treader = res.Body\n\t\t}\n\t\tall, _ := io.ReadAll(reader)\n\t\t_ = res.Body.Close()\n\t\tmsg := string(all)\n\t\tlog.Debugln(msg)\n\t\treturn res, fmt.Errorf(\"http request [%s] failure,status: %d response:%s\", URL, res.StatusCode, msg)\n\t}\n\treturn res, nil\n}\n\nvar once sync.Once\nvar httpClient *http.Client\n\nfunc HttpClient() *http.Client {\n\tonce.Do(func() {\n\t\thttpClient = NewHttpClient()\n\t\thttpClient.CheckRedirect = func(req *http.Request, via []*http.Request) error {\n\t\t\tif len(via) >= 10 {\n\t\t\t\treturn errors.New(\"stopped after 10 redirects\")\n\t\t\t}\n\t\t\treq.Header.Del(\"Referer\")\n\t\t\treturn nil\n\t\t}\n\t})","sourceCodeStart":241,"sourceCodeEnd":277,"githubUrl":"https://github.com/AlistGo/alist/blob/843d9dc8149126976b2625911e45a4d3ffd6f2f5/internal/net/serve.go#L241-L277","documentation":"Returned by the HTTP request helper in internal/net/serve.go when the response status is not a success code. It reads (and optionally gunzips) the body, closes it, logs the body, and returns the response together with an error carrying the URL, status code, and body text — so the caller can inspect res while still treating the call as failed.","triggerScenarios":"Any request through this helper receiving a non-2xx status: 401/403 auth failures, 404, 5xx from the remote; error body (JSON or HTML) is embedded in the message.","commonSituations":"Expired pre-signed URLs or tokens (403); wrong API credentials (401); remote endpoint moved (404); upstream outages (5xx); CDN error pages making the message long/noisy.","solutions":["Read the status code and response body from the error message (or the returned res) to identify the true cause.","For 401/403, refresh credentials/tokens or re-sign the URL.","For 404, verify the URL path and that the resource still exists.","For 5xx, retry with backoff or check upstream health."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"res, err := HttpRequest(...)\nif err != nil {\n    if res != nil {\n        switch res.StatusCode {\n        case 401, 403: // refresh credentials and retry once\n        case 429, 502, 503, 504: // backoff and retry\n        default: // permanent, surface body\n        }\n    }\n}","preventionTips":["Inspect res.StatusCode (the response is returned alongside the error) rather than parsing the message.","Refresh tokens/pre-signed URLs proactively before expiry.","Cap logged body size to avoid log flooding from HTML error pages."],"tags":["network","http","api","go"],"backgroundTag":null,"analyzedSha":"843d9dc8149126976b2625911e45a4d3ffd6f2f5","analyzedAt":"2026-08-15T12:14:11.722Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}