AlistGo/alist · error

failed to parse response: %v

Error message

failed to parse response: %v

What it means

json.Unmarshal failed on the body returned by /upload/resumable.php. The endpoint returned something that is not the expected JSON envelope — commonly an HTML error page, an empty body, or a plain-text gateway error. Because the driver reads the whole body first, the raw payload is available but (as evidenced by commented-out debug prints) is not included in the error, making diagnosis hard.

Source

Thrown at drivers/mediafire/util.go:440

	body, err := io.ReadAll(res.Body)
	if err != nil {
		return "", fmt.Errorf("failed to read response body: %v", err)
	}

	//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)

View on GitHub (pinned to 843d9dc814)

Solutions

  1. Log/include the body snippet and status code in the error so the actual payload is visible
  2. Retry once after backoff — gateway HTML pages are almost always transient
  3. Confirm the request includes response_format=json and follows redirects properly
  4. If persistent, dump the body and compare against the current MediaFire API docs for format changes

Example fix

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

// after
if err := json.Unmarshal(body, &uploadResp); err != nil {
    return "", fmt.Errorf("failed to parse response: %v, status=%d, body=%.200s", err, res.StatusCode, body)
}
Defensive patterns

Strategy: retry

Validate before calling

// Cheap content sniff before unmarshal
if len(body) == 0 { return errors.New("empty response body") }
if bytes.HasPrefix(bytes.TrimSpace(body), []byte("<")) {
    return fmt.Errorf("non-JSON (HTML) response, status=%d", res.StatusCode)
}

Try / catch

// Retry once on HTML/empty bodies (gateway blips), fail fast on real JSON errors
if err := json.Unmarshal(body, &v); err != nil {
    if isTransientBody(body) { return retryWithBackoff(...) }
    return fmt.Errorf("parse failed: %v body=%.200s", err, body)
}

Prevention

When it happens

Trigger: MediaFire or an intermediary (CDN/WAF) returning HTML for a 502/503; Content-Type mismatches when the API changes; empty body on early connection close; XML or error format returned because response_format was not honored.

Common situations: Transient gateway errors from mediafire.com; API contract changes after MediaFire updates; rate limiting responses that are HTML interstitials; response_format=json omitted or overridden by a redirect.

Understand the failure class

Related errors


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