AlistGo/alist · error

resumable upload failed with status %d

Error message

resumable upload failed with status %d

What it means

The resumable upload unit POST returned an HTTP status other than 200. The body was already read and parsed (JSON unmarshal happens before this check), so the status is a definitive HTTP-level rejection: auth failure (401/403), bad request (400), rate limit (429), or server error (5xx). The key from the parsed body is not returned in this case.

Source

Thrown at drivers/mediafire/util.go:444

	}

	//fmt.Printf("MediaFire resumable upload response (status %d): %s\n", res.StatusCode, string(body))

	var uploadResp struct {
		Response struct {
			Doupload struct {
				Key string `json:"key"`
			} `json:"doupload"`
			Result string `json:"result"`
		} `json:"response"`
	}

	if err := json.Unmarshal(body, &uploadResp); err != nil {
		return "", fmt.Errorf("failed to parse response: %v", err)
	}

	if res.StatusCode != 200 {
		return "", fmt.Errorf("resumable upload failed with status %d", res.StatusCode)
	}

	return uploadResp.Response.Doupload.Key, nil
}

func (d *Mediafire) uploadUnits(ctx context.Context, file *os.File, checkResp *MediafireCheckResponse, filename, fileHash, folderKey string, up driver.UpdateProgress) (string, error) {
	unitSize, _ := strconv.ParseInt(checkResp.Response.ResumableUpload.UnitSize, 10, 64)
	numUnits, _ := strconv.Atoi(checkResp.Response.ResumableUpload.NumberOfUnits)
	uploadKey := checkResp.Response.ResumableUpload.UploadKey

	stringWords := checkResp.Response.ResumableUpload.Bitmap.Words
	intWords := make([]int, len(stringWords))
	for i, word := range stringWords {
		intWords[i], _ = strconv.Atoi(word)
	}

	var finalUploadKey string

View on GitHub (pinned to 843d9dc814)

Solutions

  1. Branch on the status: 401/403 → refresh session+action token then retry; 429 → backoff and slow the unit cadence; 5xx → retry with backoff; 400 → fix the request construction
  2. Include the response body in the error message (it is already read) for precise diagnosis
  3. Re-run uploadCheck if the upload key or bitmap state may have expired
  4. For very large files, cap concurrent unit uploads and add per-request timeouts

Example fix

// before
if res.StatusCode != 200 {
    return "", fmt.Errorf("resumable upload failed with status %d", res.StatusCode)
}

// after
if res.StatusCode != 200 {
    return "", fmt.Errorf("resumable upload failed with status %d: %.200s", res.StatusCode, body)
}
Defensive patterns

Strategy: retry

Validate before calling

// Classify status before deciding to retry
switch {
case res.StatusCode == 401 || res.StatusCode == 403: refreshCreds()
case res.StatusCode == 429: return errRateLimited // backoff, do not fail
case res.StatusCode >= 500: return errTransient
}

Try / catch

// status-aware retry policy
err := d.resumableUpload(...)
for i := 0; i < 3 && isRetriableStatus(err); i++ {
    if needsRelogin(err) { d.relogin() }
    time.Sleep(backoff(i))
    err = d.resumableUpload(...)
}

Prevention

When it happens

Trigger: Expired action token or session producing 401; malformed unit headers or wrong Content-Range for 400; 429 from uploading units too fast; 5xx during MediaFire maintenance windows.

Common situations: Long uploads where the action token lapsed mid-transfer; parallel unit uploads tripping rate limits; unit boundary arithmetic off-by-one producing rejected requests; transient 502s behind MediaFire's CDN.

Related errors


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