pocketbase/pocketbase · error

the WriterOptions.ContentMD5 you specified (%X) did not matc

Error message

the WriterOptions.ContentMD5 you specified (%X) did not match what was written (%X)

What it means

Returned by blob.Writer.Close when the user supplied WriterOptions.ContentMD5 and the MD5 hash of the bytes actually written does not match it. The writer cancels its context and closes/aborts the driver write, so no corrupt object is committed. This is an integrity check failure: what you wrote is not what you promised.

Source

Thrown at tools/filesystem/blob/writer.go:123

// Close closes the blob writer. The write operation is not guaranteed
// to have succeeded until Close returns with no error.
//
// Close may return an error if the context provided to create the
// Writer is canceled or reaches its deadline.
func (w *Writer) Close() (err error) {
	w.closed = true

	// Verify the MD5 hash of what was written matches the ContentMD5 provided by the user.
	if len(w.contentMD5) > 0 {
		md5sum := w.md5hash.Sum(nil)
		if !bytes.Equal(md5sum, w.contentMD5) {
			// No match! Return an error, but first cancel the context and call the
			// driver's Close function to ensure the write is aborted.
			w.cancel()
			if w.w != nil {
				_ = w.w.Close()
			}
			return fmt.Errorf("the WriterOptions.ContentMD5 you specified (%X) did not match what was written (%X)", w.contentMD5, md5sum)
		}
	}

	defer w.cancel()

	if w.w != nil {
		return wrapError(w.drv, w.w.Close(), w.key)
	}

	if _, err := w.open(w.buf.Bytes()); err != nil {
		return err
	}

	return wrapError(w.drv, w.w.Close(), w.key)
}

// open tries to detect the MIME type of p and write it to the blob.
// The error it returns is wrapped.

View on GitHub (pinned to 5d217ddb50)

Solutions

  1. Recompute the MD5 from the exact byte stream you pass to Write (hash while writing: io.MultiWriter(w, md5hash)).
  2. Verify the hash format: ContentMD5 must be the raw 16-byte MD5 digest, not a hex string.
  3. If the source file may change, hash and upload from the same opened file handle / buffered snapshot.

Example fix

// before
h := md5.Sum([]byte("v1 of file"))
w, _ := bucket.NewWriter(ctx, key, &blob.WriterOptions{ContentMD5: h[:]})
w.Write(fileBytesV2) // mismatch

// after
var buf bytes.Buffer
buf.Write(fileBytes) // snapshot once
h := md5.Sum(buf.Bytes())
w, _ := bucket.NewWriter(ctx, key, &blob.WriterOptions{ContentMD5: h[:]})
buf.WriteTo(w)
Defensive patterns

Strategy: validation

Validate before calling

h := md5.Sum(data)
w, err := bucket.NewWriter(ctx, key, &blob.WriterOptions{ContentMD5: h[:]})
w.Write(data)

Try / catch

err := w.Close()
if err != nil && strings.Contains(err.Error(), "ContentMD5") {
    // data corrupted between hash and write: re-hash the actual bytes and retry once
}

Prevention

When it happens

Trigger: NewWriter(ctx, key, &blob.WriterOptions{ContentMD5: expectedSum}) then writing bytes whose MD5 differs — wrong hash computed upstream, hash of a different file version, bytes mutated in transit (rare), or the MD5 passed in the wrong byte order/format.

Common situations: Upload pipelines where a metadata service provides the MD5 but the file was regenerated; copying hashes between hex and raw-byte representations; concurrent modification of the source file between hashing and uploading.

Related errors


AI-assisted analysis of pocketbase/pocketbase@5d217ddb50 (2026-08-15). Data as JSON: /api/errors/18baa56f324a31c2. Report an issue: GitHub.