{"record":{"id":"cecd712e442b8154","repo":"nats-io/nats-server","slug":"error-closing-compression-writer-w","errorCode":null,"errorMessage":"error closing compression writer: %w","messagePattern":"error closing compression writer: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/filestore.go","lineNumber":14526,"sourceCode":"\t\treturn buf, nil\n\tcase S2Compression:\n\t\twriter = s2.NewWriter(&output)\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"compression algorithm not known\")\n\t}\n\n\tinput := bytes.NewReader(buf[:bodyLen])\n\tchecksum := buf[bodyLen:]\n\n\t// Compress the block content, but don't compress the checksum.\n\t// We will preserve it at the end of the block as-is.\n\tif n, err := io.CopyN(writer, input, bodyLen); err != nil {\n\t\treturn nil, fmt.Errorf(\"error writing to compression writer: %w\", err)\n\t} else if n != bodyLen {\n\t\treturn nil, fmt.Errorf(\"short write on body (%d != %d)\", n, bodyLen)\n\t}\n\tif err := writer.Close(); err != nil {\n\t\treturn nil, fmt.Errorf(\"error closing compression writer: %w\", err)\n\t}\n\n\t// Now add the checksum back onto the end of the block.\n\tif n, err := output.Write(checksum); err != nil {\n\t\treturn nil, fmt.Errorf(\"error writing checksum: %w\", err)\n\t} else if n != checksumSize {\n\t\treturn nil, fmt.Errorf(\"short write on checksum (%d != %d)\", n, checksumSize)\n\t}\n\n\treturn output.Bytes(), nil\n}\n\nfunc (alg StoreCompression) Decompress(buf []byte) ([]byte, error) {\n\tif len(buf) < checksumSize {\n\t\treturn nil, fmt.Errorf(\"compressed buffer is too short\")\n\t}\n\tbodyLen := int64(len(buf) - checksumSize)\n\tinput := bytes.NewReader(buf[:bodyLen])","sourceCodeStart":14508,"sourceCodeEnd":14544,"githubUrl":"https://github.com/nats-io/nats-server/blob/3a66a489d262bf89b71a71c955c94920394532f3/server/filestore.go#L14508-L14544","documentation":"This error is returned by StoreCompression's compress path (server/filestore.go) when writer.Close() fails after the compressed body was fully written. Closing a compression writer (e.g. s2.Writer) flushes internal buffers and writes the stream trailer; if that flush fails the block would be corrupt, so the library refuses to return it. The underlying writer error is wrapped with %w so errors.Is/As still work.","triggerScenarios":"io.Writer to Close (the compression writer over an output buffer or stream) returns a non-nil error when closed after a successful io.CopyN of bodyLen bytes during block compression in the filestore.","commonSituations":"Disk-full or I/O errors when output is a file-backed writer, corruption of an in-memory buffer implementation, or a custom io.WriteCloser whose Close does an extra flush that fails.","solutions":["Inspect the wrapped cause with errors.Is/As on the returned error to find the real writer failure","Verify the destination writer (output buffer/file/stream) has space and is healthy","Retry the block compression once; transient I/O errors may clear","If using a custom writer, ensure Close only errors on genuine flush failures"],"exampleFix":"// before\nif err := writer.Close(); err != nil {\n    return nil, fmt.Errorf(\"error closing compression writer: %w\", err)\n}\n// after\nif err := writer.Close(); err != nil {\n    if errors.Is(err, os.ErrNoSpace) {\n        return nil, fmt.Errorf(\"compression close failed, disk full: %w\", err)\n    }\n    return nil, fmt.Errorf(\"error closing compression writer: %w\", err)\n}","handlingStrategy":"try-catch","validationCode":"if outWriter == nil || unreliable { return errors.New(\"need healthy output writer before compressing\") }","typeGuard":"func isCompressionCloseError(err error) bool { return err != nil && strings.Contains(err.Error(), \"error closing compression writer\") }","tryCatchPattern":"data, err := alg.Compress(block)\nif err != nil {\n    var ce *fsErr\n    if errors.As(err, &ce) && strings.Contains(err.Error(), \"closing compression writer\") {\n        // retry or surface storage I/O problem\n    }\n    return err\n}","preventionTips":["Compress to bytes.Buffer-backed writers which rarely fail on Close","Monitor disk space where the filestore writes","Treat any wrapped Close error as a storage-layer alarm, not a data problem"],"tags":["io","compression","filestore"],"backgroundTag":"compression-writer-close-failed","analyzedSha":"3a66a489d262bf89b71a71c955c94920394532f3","analyzedAt":"2026-09-02T04:41:54.247Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}