{"record":{"id":"614e13639f41d555","repo":"AlistGo/alist","slug":"bad-status-s-body-s","errorCode":null,"errorMessage":"bad status: %s, body: %s","messagePattern":"bad status: (.+?), body: (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"drivers/halalcloud/util.go","lineNumber":240,"sourceCode":"\tif addr == nil {\n\t\treturn nil, errors.New(\"addr is nil\")\n\t}\n\n\tclient := http.Client{\n\t\tTimeout: time.Duration(60 * time.Second), // Set timeout to 5 seconds\n\t}\n\tresp, err := client.Get(addr.DownloadAddress)\n\tif err != nil {\n\n\t\treturn nil, err\n\t}\n\tdefer resp.Body.Close()\n\tbody, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn nil, fmt.Errorf(\"bad status: %s, body: %s\", resp.Status, body)\n\t}\n\n\tif addr.Encrypt > 0 {\n\t\tcd := uint8(addr.Encrypt)\n\t\tfor idx := 0; idx < len(body); idx++ {\n\t\t\tbody[idx] = body[idx] ^ cd\n\t\t}\n\t}\n\n\tif addr.StoreType != 10 {\n\n\t\tsourceCid, err := cid.Decode(addr.Identity)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tcheckCid, err := sourceCid.Prefix().Sum(body)\n\t\tif err != nil {\n\t\t\treturn nil, err","sourceCodeStart":222,"sourceCodeEnd":258,"githubUrl":"https://github.com/AlistGo/alist/blob/843d9dc8149126976b2625911e45a4d3ffd6f2f5/drivers/halalcloud/util.go#L222-L258","documentation":"Thrown by HalalCloud's slice downloader when the HTTP GET to addr.DownloadAddress returns any status other than 200. The full response body is included, which often contains the CDN/storage node's own error text. This is a transport-level failure against the per-slice download URL, before any decrypt or CID verification happens.","triggerScenarios":"Expired signed download URL (addresses are short-lived), storage node temporarily down (5xx), rate limiting (429), or the file being deleted between address issuance and fetch.","commonSituations":"Long-running downloads that outlive the URL signature TTL; retrying after a pause; CDN node maintenance; aggressive parallel slice fetching triggering 429s.","solutions":["Read the body in the message — 403 signature-expired vs 429 vs 500 each imply different fixes.","Re-request the download address (re-run the address/API call) to get a fresh signed URL, then retry the slice.","Add exponential backoff retry around the slice fetch for 429/5xx.","Reduce slice-parallelism if rate limited."],"exampleFix":"// before\nbody, err := downloadSlice(client, addr)\nif err != nil { return err }\n\n// after: refresh the signed address on non-200 and retry once\nbody, err := downloadSlice(client, addr)\nif err != nil && strings.Contains(err.Error(), \"bad status\") {\n    addr, aerr := refreshDownloadAddress(ctx, fileID)\n    if aerr != nil { return aerr }\n    body, err = downloadSlice(client, addr)\n}\nif err != nil { return err }","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"body, err := fetchSlice(client, addr)\nif err != nil && strings.Contains(err.Error(), \"bad status\") {\n    if isRetryableStatus(err) { // 429/5xx embedded in message\n        time.Sleep(backoff)\n        addr, _ = refreshAddress(ctx)\n        body, err = fetchSlice(client, addr)\n    }\n}\nif err != nil { return err }","preventionTips":["Treat download addresses as short-lived: fetch them right before each slice","Retry with backoff on 429/5xx","Limit slice fetch parallelism"],"tags":["halalcloud","http-status","signed-url","download"],"backgroundTag":null,"analyzedSha":"843d9dc8149126976b2625911e45a4d3ffd6f2f5","analyzedAt":"2026-08-15T12:14:11.722Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}