AlistGo/alist · error

bad status: %s, body: %s

Error message

bad status: %s, body: %s

What it means

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.

Source

Thrown at drivers/halalcloud/util.go:240

	if addr == nil {
		return nil, errors.New("addr is nil")
	}

	client := http.Client{
		Timeout: time.Duration(60 * time.Second), // Set timeout to 5 seconds
	}
	resp, err := client.Get(addr.DownloadAddress)
	if err != nil {

		return nil, err
	}
	defer resp.Body.Close()
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("bad status: %s, body: %s", resp.Status, body)
	}

	if addr.Encrypt > 0 {
		cd := uint8(addr.Encrypt)
		for idx := 0; idx < len(body); idx++ {
			body[idx] = body[idx] ^ cd
		}
	}

	if addr.StoreType != 10 {

		sourceCid, err := cid.Decode(addr.Identity)
		if err != nil {
			return nil, err
		}
		checkCid, err := sourceCid.Prefix().Sum(body)
		if err != nil {
			return nil, err

View on GitHub (pinned to 843d9dc814)

Solutions

  1. Read the body in the message — 403 signature-expired vs 429 vs 500 each imply different fixes.
  2. Re-request the download address (re-run the address/API call) to get a fresh signed URL, then retry the slice.
  3. Add exponential backoff retry around the slice fetch for 429/5xx.
  4. Reduce slice-parallelism if rate limited.

Example fix

// before
body, err := downloadSlice(client, addr)
if err != nil { return err }

// after: refresh the signed address on non-200 and retry once
body, err := downloadSlice(client, addr)
if err != nil && strings.Contains(err.Error(), "bad status") {
    addr, aerr := refreshDownloadAddress(ctx, fileID)
    if aerr != nil { return aerr }
    body, err = downloadSlice(client, addr)
}
if err != nil { return err }
Defensive patterns

Strategy: retry

Try / catch

body, err := fetchSlice(client, addr)
if err != nil && strings.Contains(err.Error(), "bad status") {
    if isRetryableStatus(err) { // 429/5xx embedded in message
        time.Sleep(backoff)
        addr, _ = refreshAddress(ctx)
        body, err = fetchSlice(client, addr)
    }
}
if err != nil { return err }

Prevention

When it happens

Trigger: 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.

Common situations: Long-running downloads that outlive the URL signature TTL; retrying after a pause; CDN node maintenance; aggressive parallel slice fetching triggering 429s.

Related errors


AI-assisted analysis of AlistGo/alist@843d9dc814 (2026-08-15). Data as JSON: /api/errors/614e13639f41d555. Report an issue: GitHub.