juicedata/juicefs · error
No ETag
Error message
No ETag
What it means
ufile.UploadPart expects the UCloud UFile response to carry an ETag header for each uploaded part; the ETag is required to complete the multipart upload. If the response has no Etag header, the part result cannot be built and the upload fails.
Source
Thrown at pkg/object/ufile.go:300
}
return &MultipartUpload{UploadID: out.UploadId, MinPartSize: int64(out.BlkSize), MaxCount: 1000000}, nil
}
func (u *ufile) UploadPart(ctx context.Context, key string, uploadID string, num int, data []byte) (*Part, error) {
// UFile require the PartNumber to start from 0 (continuous)
num--
path := fmt.Sprintf("%s?uploadId=%s&partNumber=%d", key, uploadID, num)
resp, err := u.request(ctx, "PUT", path, bytes.NewReader(data), nil)
if err != nil {
return nil, err
}
defer cleanup(resp)
if resp.StatusCode != 200 {
return nil, fmt.Errorf("UploadPart: %s", parseError(resp).Error())
}
etags := resp.Header["Etag"]
if len(etags) < 1 {
return nil, errors.New("No ETag")
}
return &Part{Num: num, Size: len(data), ETag: strings.Trim(etags[0], "\"")}, nil
}
func (u *ufile) AbortUpload(ctx context.Context, key string, uploadID string) {
_, _ = u.request(ctx, "DELETE", key+"?uploads="+uploadID, nil, nil)
}
func (u *ufile) CompleteUpload(ctx context.Context, key string, uploadID string, parts []*Part) error {
etags := make([]string, len(parts))
for i, p := range parts {
etags[i] = p.ETag
}
resp, err := u.request(ctx, "POST", key+"?uploadId="+uploadID, bytes.NewReader([]byte(strings.Join(etags, ","))), nil)
if err != nil {
return err
}
defer cleanup(resp)View on GitHub (pinned to c9a67b23e8)
Solutions
- Verify the bucket's domain/endpoint points directly at UFile and no proxy strips the Etag header
- Re-run the upload; transient gateway issues may drop headers
- Check response with curl to confirm the Etag header is present at your endpoint
- Capture the raw HTTP response for debugging and report to UFile support if the service omits ETag
Defensive patterns
Strategy: retry
Validate before calling
resp, _ := http.Head(endpoint)
if resp.Header.Get("Etag") == "" {
// endpoint/proxy strips headers — fix config before uploading
} Try / catch
part, err := store.UploadPart(ctx, key, uploadID, num, data)
if err != nil && strings.Contains(err.Error(), "No ETag") {
// retry once; else fail with clear diagnostics
part, err = store.UploadPart(ctx, key, uploadID, num, data)
} Prevention
- Point UFile buckets at native UFile endpoints, not header-stripping proxies
- Test endpoint responses with curl before large multipart uploads
- Monitor for repeated No ETag failures indicating infrastructure changes
When it happens
Trigger: Calling UploadPart against a UFile endpoint whose successful (200) response omits the Etag header — e.g. a proxy/gateway stripping headers, or a non-standard endpoint returning 200 with an error body.
Common situations: Corporate proxies or CDNs in front of UFile that strip headers; misconfigured UFile bucket domains; region/endpoint mismatches returning unusual responses.
Related errors
- UploadPart: %s
- CompleteMultipart: %s
- ${errMsg}
- create multipart upload failed: %s
- multipart upload error: %s
AI-assisted analysis of juicedata/juicefs@c9a67b23e8 (2026-09-06).
Data as JSON: /api/errors/c392c45df5c77865.
Report an issue: GitHub.