AlistGo/alist · error
faild to get ETag from header
Error message
faild to get ETag from header
What it means
In Cloudreve S3-like policy upload, a chunk PUT returned HTTP 200 but the response had no ETag header, so the driver cannot assemble the multipart completion manifest. ETags are required to complete an S3 multipart upload.
Source
Thrown at drivers/cloudreve/util.go:414
req.ContentLength = byteSize
finish += 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, error %d", maxRetries, res.StatusCode)
}
backoff := time.Duration(1<<retryCount) * time.Second
utils.Log.Warnf("[Cloudreve-S3] server errors %d while uploading, 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(stream.GetSize()))
chunk++
}
}
// s3LikeFinishUpload
// https://github.com/cloudreve/frontend/blob/b485bf297974cbe4834d2e8e744ae7b7e5b2ad39/src/component/Uploader/core/api/index.ts#L204-L252
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
- Verify with a manual multipart PUT (curl -X PUT with -D -) whether the endpoint really returns ETag; if not, switch the Cloudrebve storage policy to a provider that does.
- Remove any proxy/CDN layer in front of the S3 endpoint that could strip the ETag response header.
- Update the S3-compatible server (MinIO/Ceph) to a version known to return ETag for UploadPart.
- As a workaround, use a different upload policy (local or OneDrive) in Cloudreve for this storage.
Example fix
# verify ETag presence on chunk upload curl -sS -D - -o /dev/null -X PUT \ -H 'Authorization: ...' \ --data-binary @chunk.bin \ 'https://s3.example.com/bucket/key?partNumber=1&uploadId=...' # -> HTTP/1.1 200 OK # -> ETag: "abc123..." (must be present)
Defensive patterns
Strategy: validation
Validate before calling
// before switching a policy to S3-like, confirm the backend returns ETag on part PUT
resp, err := http.NewRequest(http.MethodPut, partURL, bytes.NewReader(chunk))
// ... execute ...
if resp.Header.Get("ETag") == "" {
return errors.New("backend strips ETag; multipart completion will fail — pick another endpoint")
} Try / catch
etag := res.Header.Get("ETag")
if etag == "" {
if sc := res.Header.Get("X-Amz-Etag"); sc != "" { etag = sc } // some clones use alt casing/keys
}
if etag == "" {
return errors.New("faild to get ETag from header")
} Prevention
- Verify ETag presence with curl before adopting an S3-compatible backend
- Keep proxies off the S3 data path so headers survive
- Prefer mainstream S3 providers for multipart policies
When it happens
Trigger: upS3-like loop: res.Header.Get("ETag") == "" with StatusCode 200. Happens when the S3-compatible backend (or a proxy/CDN in front of it) omits ETag on PutObject/UploadPart responses.
Common situations: Non-AWS S3 clones (some MinIO gateway modes, certain object storage vendors) that strip or never set ETag; proxy (nginx/Cloudflare) dropping the header; servers that only return ETag when the request supplies Content-MD5.
Related errors
- faild to get ETag from header
- r.Msg
- can not get captcha
- ocr error:" + jsoniter.Get(vRes.Body(), "msg").ToString()
- res.Status
AI-assisted analysis of AlistGo/alist@843d9dc814 (2026-08-15).
Data as JSON: /api/errors/8602758953275846.
Report an issue: GitHub.