{"record":{"id":"18baa56f324a31c2","repo":"pocketbase/pocketbase","slug":"the-writeroptions-contentmd5-you-specified-x-di","errorCode":null,"errorMessage":"the WriterOptions.ContentMD5 you specified (%X) did not match what was written (%X)","messagePattern":"the WriterOptions\\.ContentMD5 you specified \\(%X\\) did not match what was written \\(%X\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"tools/filesystem/blob/writer.go","lineNumber":123,"sourceCode":"// Close closes the blob writer. The write operation is not guaranteed\n// to have succeeded until Close returns with no error.\n//\n// Close may return an error if the context provided to create the\n// Writer is canceled or reaches its deadline.\nfunc (w *Writer) Close() (err error) {\n\tw.closed = true\n\n\t// Verify the MD5 hash of what was written matches the ContentMD5 provided by the user.\n\tif len(w.contentMD5) > 0 {\n\t\tmd5sum := w.md5hash.Sum(nil)\n\t\tif !bytes.Equal(md5sum, w.contentMD5) {\n\t\t\t// No match! Return an error, but first cancel the context and call the\n\t\t\t// driver's Close function to ensure the write is aborted.\n\t\t\tw.cancel()\n\t\t\tif w.w != nil {\n\t\t\t\t_ = w.w.Close()\n\t\t\t}\n\t\t\treturn fmt.Errorf(\"the WriterOptions.ContentMD5 you specified (%X) did not match what was written (%X)\", w.contentMD5, md5sum)\n\t\t}\n\t}\n\n\tdefer w.cancel()\n\n\tif w.w != nil {\n\t\treturn wrapError(w.drv, w.w.Close(), w.key)\n\t}\n\n\tif _, err := w.open(w.buf.Bytes()); err != nil {\n\t\treturn err\n\t}\n\n\treturn wrapError(w.drv, w.w.Close(), w.key)\n}\n\n// open tries to detect the MIME type of p and write it to the blob.\n// The error it returns is wrapped.","sourceCodeStart":105,"sourceCodeEnd":141,"githubUrl":"https://github.com/pocketbase/pocketbase/blob/5d217ddb50cb144d80a5d0b0bdf11b52b2c3e457/tools/filesystem/blob/writer.go#L105-L141","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Recompute the MD5 from the exact byte stream you pass to Write (hash while writing: io.MultiWriter(w, md5hash)).","Verify the hash format: ContentMD5 must be the raw 16-byte MD5 digest, not a hex string.","If the source file may change, hash and upload from the same opened file handle / buffered snapshot."],"exampleFix":"// before\nh := md5.Sum([]byte(\"v1 of file\"))\nw, _ := bucket.NewWriter(ctx, key, &blob.WriterOptions{ContentMD5: h[:]})\nw.Write(fileBytesV2) // mismatch\n\n// after\nvar buf bytes.Buffer\nbuf.Write(fileBytes) // snapshot once\nh := md5.Sum(buf.Bytes())\nw, _ := bucket.NewWriter(ctx, key, &blob.WriterOptions{ContentMD5: h[:]})\nbuf.WriteTo(w)","handlingStrategy":"validation","validationCode":"h := md5.Sum(data)\nw, err := bucket.NewWriter(ctx, key, &blob.WriterOptions{ContentMD5: h[:]})\nw.Write(data)","typeGuard":null,"tryCatchPattern":"err := w.Close()\nif err != nil && strings.Contains(err.Error(), \"ContentMD5\") {\n    // data corrupted between hash and write: re-hash the actual bytes and retry once\n}","preventionTips":["Compute the MD5 over the same buffer you hand to Write (io.MultiWriter pattern).","Store digests as raw 16 bytes, not hex strings.","Snapshot mutable sources before hashing + uploading."],"tags":["go","blob","integrity","md5","upload"],"backgroundTag":null,"analyzedSha":"5d217ddb50cb144d80a5d0b0bdf11b52b2c3e457","analyzedAt":"2026-08-15T10:06:33.165Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}