AlistGo/alist · error

faild to get ETag from header

Error message

faild to get ETag from header

What it means

CloudreveV4 S3-like upload: a chunk PUT returned 200 but no ETag response header, so the multipart completion manifest cannot be built and the driver errors out. Same root pattern as the V3 S3 driver's ETag check, on the V4 callback path.

Source

Thrown at drivers/cloudreve_v4/util.go:431

		req = req.WithContext(ctx)
		req.ContentLength = byteSize
		res, err := base.HttpClient.Do(req)
		if err != nil {
			return err
		}
		etag := res.Header.Get("ETag")
		res.Body.Close()
		switch {
		case res.StatusCode != 200:
			retryCount++
			if retryCount > maxRetries {
				return fmt.Errorf("upload failed after %d retries due to server errors", maxRetries)
			}
			backoff := time.Duration(1<<retryCount) * time.Second
			utils.Log.Warnf("server error %d, retrying after %v...", res.StatusCode, backoff)
			time.Sleep(backoff)
		case etag == "":
			return errors.New("faild to get ETag from header")
		default:
			retryCount = 0
			etags = append(etags, etag)
			finish += byteSize
			up(float64(finish) * 100 / float64(file.GetSize()))
			chunk++
		}
	}

	// s3LikeFinishUpload
	bodyBuilder := &strings.Builder{}
	bodyBuilder.WriteString("<CompleteMultipartUpload>")
	for i, etag := range etags {
		bodyBuilder.WriteString(fmt.Sprintf(
			`<Part><PartNumber>%d</PartNumber><ETag>%s</ETag></Part>`,
			i+1, // PartNumber 从 1 开始
			etag,
		))

View on GitHub (pinned to 843d9dc814)

Solutions

  1. Verify with curl -X PUT -D - that the endpoint returns an ETag on part upload.
  2. Remove header-stripping proxies from the path to the S3 endpoint.
  3. Upgrade the S3-compatible server to a version that emits ETag for multipart parts.
  4. Switch the Cloudrebve V4 policy to local/OneDrive storage if the backend cannot be fixed.
Defensive patterns

Strategy: validation

Validate before calling

etag := res.Header.Get("ETag")
if etag == "" { etag = res.Header.Get("X-Amz-Etag") } // tolerate alt headers
if etag == "" { return errors.New("faild to get ETag from header") }

Try / catch

if err := d.upS3Like(...); err != nil {
    if err.Error() == "faild to get ETag from header" {
        // backend is dropping ETag; no point retrying — switch endpoint/policy
        return errors.New("S3 backend omits ETag on part upload; use an ETag-compliant endpoint")
    }
    return err
}

Prevention

When it happens

Trigger: upS3-like loop: res.Header.Get("ETag") == "" with a 200 status. Produced by S3-compatible backends or intermediary proxies that omit ETag on UploadPart/PutObject responses.

Common situations: Exotic S3 clones that skip ETag; nginx/CDN stripping the header; gateway-mode MinIO in front of another store; header case/encoding quirks in nonstandard implementations.

Related errors


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