{"record":{"id":"c3c29e8d46bde2e2","repo":"kopia/kopia","slug":"invalid-compression-header-expected-x-but-got-x","errorCode":null,"errorMessage":"invalid compression header, expected %x but got %x","messagePattern":"invalid compression header, expected %x but got %x","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"repo/compression/compressor.go","lineNumber":115,"sourceCode":"\t\treturn false\n\t}\n\n\treturn !isUnsupported[c.HeaderID()]\n}\n\nfunc mustSucceed(err error) {\n\timpossible.PanicOnError(err)\n}\n\nfunc verifyCompressionHeader(reader io.Reader, want []byte) error {\n\tvar actual [compressionHeaderSize]byte\n\n\tif _, err := io.ReadFull(reader, actual[:]); err != nil {\n\t\treturn errors.Wrap(err, \"error reading compression header\")\n\t}\n\n\tif !bytes.Equal(actual[:], want) {\n\t\treturn errors.Errorf(\"invalid compression header, expected %x but got %x\", want, actual[:])\n\t}\n\n\treturn nil\n}\n","sourceCodeStart":97,"sourceCodeEnd":120,"githubUrl":"https://github.com/kopia/kopia/blob/82495e54b584c1ef6073c9e1be048f57f8aef078/repo/compression/compressor.go#L97-L120","documentation":"The stream's actual 4-byte compression header did not equal the expected header for the compressor performing Decompress. The data was readable, but it was compressed with a different scheme than the one the caller used (or the bytes are not this library's compressed format at all).","triggerScenarios":"Calling a specific compressor's Decompress (withHeader true) on data written by a different compressor — e.g. gzip.Decompress on zstd-compressed bytes; passing plaintext or another format's magic (e.g. gzip's 1f8b) where the library's 4-byte ID header is expected.","commonSituations":"Config change between write and read (default compression switched from snappy to zstd); reading legacy blobs written with an older scheme; hand-rolled code that strips or misaligns headers before calling Decompress.","solutions":["Read the actual 4-byte header and dispatch via compression.DecompressByHeader instead of hard-coding one compressor.","Ensure writer and reader use the same configured compression scheme (align config across services/versions).","Use the object reader (newRawReader path) which self-selects the compressor, rather than calling a specific compressor directly.","Migrate/re-compress legacy blobs to the current scheme."],"exampleFix":"// before\nerr := compression.ByName[\"zstd\"].Decompress(out, r, true) // header mismatch on snappy blob\n// after\nerr := compression.DecompressByHeader(out, r) // dispatches on actual header","handlingStrategy":"validation","validationCode":"hdr := make([]byte, 4)\nif _, err := io.ReadFull(r, hdr); err != nil { return err }\nexpected := compression.ByName[\"zstd\"].Header() // scheme you intend to use\nif !bytes.Equal(hdr, expected) {\n    // fall back to header-driven dispatch instead of hard-coded compressor\n    r = io.MultiReader(bytes.NewReader(hdr), r)\n    return compression.DecompressByHeader(out, r)\n}","typeGuard":"func matchesScheme(r io.Reader, want []byte) (bool, io.Reader) {\n    b := make([]byte, len(want))\n    if _, err := io.ReadFull(r, b); err != nil { return false, r }\n    return bytes.Equal(b, want), io.MultiReader(bytes.NewReader(b), r)\n}","tryCatchPattern":"if err := comp.Decompress(out, r, true); err != nil {\n    if strings.Contains(err.Error(), \"invalid compression header\") {\n        r.Seek(0, io.SeekStart)\n        return compression.DecompressByHeader(out, r) // dispatch by actual header\n    }\n    return err\n}","preventionTips":["Use DecompressByHeader instead of a specific compressor when scheme may vary.","Keep compression config identical across service versions.","Re-compress legacy blobs after scheme migrations."],"tags":["compression","header-mismatch","version-skew"],"backgroundTag":"checksum-mismatch","analyzedSha":"82495e54b584c1ef6073c9e1be048f57f8aef078","analyzedAt":"2026-09-07T20:35:21.689Z","contentChangedAt":"2026-09-07T20:35:21.689Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}