juicedata/juicefs · error

unexpected ETag: %s != %s

Error message

unexpected ETag: %s != %s

What it means

OBS Put verifies that Huawei OBS actually stored the bytes it claims: when checkEtag is enabled (bucket has no server-side encryption), the returned ETag must equal the hex MD5 of the uploaded body. A mismatch means the object was corrupted, transformed (e.g. encryption), or the response ETag is not an MD5, so Put returns 'unexpected ETag: <got> != <expected>'.

Source

Thrown at pkg/object/obs.go:178

	mimeType := utils.GuessMimeType(key)
	params := &obs.PutObjectInput{}
	params.Bucket = s.bucket
	params.Key = key
	params.Body = body
	params.ContentLength = vlen
	params.ContentMD5 = base64.StdEncoding.EncodeToString(sum[:])
	params.ContentType = mimeType
	t := s.getRuntimeTier(ctx)
	params.StorageClass = obs.StorageClassType(t.Sc)
	var resp *obs.PutObjectOutput
	var err error
	if t.encodedTag != "" {
		resp, err = s.c.PutObject(params, obs.WithHeader(obsTaggingHeader, []string{t.encodedTag}))
	} else {
		resp, err = s.c.PutObject(params)
	}
	if err == nil && s.checkEtag && strings.Trim(resp.ETag, "\"") != obs.Hex(sum) {
		err = fmt.Errorf("unexpected ETag: %s != %s", strings.Trim(resp.ETag, "\""), obs.Hex(sum))
	}
	if resp != nil {
		attrs := ApplyGetters(getters...)
		attrs.SetRequestID(resp.RequestId).SetStorageClass(getOrDefaultScValue(string(resp.StorageClass), string(obs.StorageClassStandard)))
	}
	return err
}

func (s *obsClient) Copy(ctx context.Context, dst, src string) error {
	t := s.getRuntimeTier(ctx)
	sc := getOrDefaultScValue(t.Sc, string(obs.StorageClassStandard))
	params := &obs.CopyObjectInput{}
	params.Bucket = s.bucket
	params.Key = dst
	params.CopySourceBucket = s.bucket
	params.CopySourceKey = src
	params.StorageClass = obs.StorageClassType(sc)
	var err error

View on GitHub (pinned to c9a67b23e8)

Solutions

  1. Check whether the bucket has server-side encryption configured and set expectations accordingly
  2. Retry the upload; if it persists, inspect for content-altering proxies
  3. Compare the returned ETag manually to confirm whether it is an MD5 of the content
  4. Report/upgrade if the OBS SDK changes ETag semantics for your bucket type
Defensive patterns

Strategy: retry

Try / catch

if err := store.Put(ctx, key, body); err != nil && strings.Contains(err.Error(), "unexpected ETag") {
	// re-upload once; if persistent, check bucket encryption settings
}

Prevention

When it happens

Trigger: Calling Put on an obsStore whose bucket has bucket encryption disabled (checkEtag=true) and the response ETag (quotes stripped) does not equal obs.Hex(sum) of the local body.

Common situations: Bucket has SSE enabled but the encryption probe mis-detected it, so ETag is not an MD5; a proxy/middlebox altering content; OBS SDK returning a non-MD5 ETag; multipart-style uploads where ETag differs from plain MD5.

Understand the failure class

Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.

Related errors


AI-assisted analysis of juicedata/juicefs@c9a67b23e8 (2026-09-06). Data as JSON: /api/errors/110824baac5e955c. Report an issue: GitHub.