AlistGo/alist · error

upload failed: %w

Error message

upload failed: %w

What it means

The multipart POST of the file bytes to the upload server URL failed at the transport level (%w wraps a resty/network error). This happens before any status-code check — the request never completed successfully: DNS failure, connection reset, TLS error, or context cancellation.

Source

Thrown at drivers/darkibox/driver.go:258

		return nil, fmt.Errorf("no upload server URL returned")
	}

	// Step 2: Upload the file to the upload server
	reader := driver.NewLimitedUploadStream(ctx, &driver.ReaderUpdatingProgress{
		Reader:         file,
		UpdateProgress: up,
	})

	res, err := base.RestyClient.R().
		SetContext(ctx).
		SetMultipartField("file", file.GetName(), "", reader).
		SetMultipartFormData(map[string]string{
			"key":    d.APIKey,
			"fld_id": fldIDStr(folderID),
		}).
		Post(server.URL)
	if err != nil {
		return nil, fmt.Errorf("upload failed: %w", err)
	}
	if res.StatusCode() != http.StatusOK {
		return nil, fmt.Errorf("upload failed: http %d", res.StatusCode())
	}

	// Try to parse upload response to get the file code
	var uploadResp uploadResult
	if err := base.RestyClient.JSONUnmarshal(res.Body(), &uploadResp); err == nil && len(uploadResp.Files) > 0 {
		uf := uploadResp.Files[0]
		return &model.Object{
			ID:       encodeFileID(uf.FileCode),
			Name:     file.GetName(),
			Size:     file.GetSize(),
			IsFolder: false,
		}, nil
	}

	return &model.Object{

View on GitHub (pinned to 843d9dc814)

Solutions

  1. If the wrapped error mentions context cancellation, the upload was aborted intentionally — not a bug
  2. Retry the upload; resty-level transport errors are usually transient
  3. Check connectivity to the specific upload server host returned by /upload/server (it may differ from the API domain)
  4. For repeated resets on large files, verify MTU/proxy settings or try a smaller test file to isolate size-related drops

Example fix

// before
res, err := base.RestyClient.R().
	SetContext(ctx).
	SetMultipartField("file", file.GetName(), "", reader).
	Post(server.URL)
// after — SetRetryCount/RetryCondition can be set on a dedicated client for transient transport errors
res, err := base.RestyClient.R().
	SetContext(ctx).
	SetMultipartField("file", file.GetName(), "", reader).
	Post(server.URL)
// (wrap Put's caller with retry for "upload failed: ... connection reset" messages)
Defensive patterns

Strategy: retry

Validate before calling

parsed, err := url.Parse(server.URL)
if err != nil || parsed.Host == "" {
	return nil, errors.New("upload server URL unusable")
}

Try / catch

if err != nil && strings.Contains(err.Error(), "upload failed") {
	if errors.Is(err, context.Canceled) { return err } // user abort: do not retry
	return retryWithBackoff(ctx, upload, 3)
}

Prevention

When it happens

Trigger: resty Post() returns err on: context cancelled (user aborted upload), dial tcp timeout to the upload server host, TLS handshake failure, connection reset mid-transfer (often caused by the provider dropping large bodies), or reading from the limited stream erroring.

Common situations: Large uploads over unstable links; upload server host differs from apiBase and is blocked by firewall/GFW; proxy misconfiguration; user cancels the upload midway; disk read error while streaming the source file.

Related errors


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