{"record":{"id":"9bb0dd47db520268","repo":"nats-io/nats-server","slug":"error-closing-compression-writer-w-9bb0dd","errorCode":null,"errorMessage":"error closing compression writer: %w","messagePattern":"error closing compression writer: %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/ocsp_responsecache.go","lineNumber":355,"sourceCode":"\t\t\tc.stats.Revokes++\n\t\tcase ocsp.Unknown:\n\t\t\tc.stats.Unknowns++\n\t\t}\n\t}\n}\n\nfunc (c *LocalCache) Compress(buf []byte) ([]byte, error) {\n\tbodyLen := int64(len(buf))\n\tvar output bytes.Buffer\n\twriter := s2.NewWriter(&output)\n\tinput := bytes.NewReader(buf[:bodyLen])\n\tif n, err := io.CopyN(writer, input, bodyLen); err != nil {\n\t\treturn nil, fmt.Errorf(certidp.ErrCannotWriteCompressed, err)\n\t} else if n != bodyLen {\n\t\treturn nil, fmt.Errorf(certidp.ErrTruncatedWrite, n, bodyLen)\n\t}\n\tif err := writer.Close(); err != nil {\n\t\treturn nil, fmt.Errorf(certidp.ErrCannotCloseWriter, err)\n\t}\n\treturn output.Bytes(), nil\n}\n\nfunc (c *LocalCache) Decompress(buf []byte) ([]byte, error) {\n\tbodyLen := int64(len(buf))\n\tinput := bytes.NewReader(buf[:bodyLen])\n\treader := io.NopCloser(s2.NewReader(input))\n\toutput, err := io.ReadAll(reader)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(certidp.ErrCannotReadCompressed, err)\n\t}\n\treturn output, reader.Close()\n}\n\nfunc (c *LocalCache) loadCache(s *Server) {\n\td := s.opts.OCSPCacheConfig.LocalStore\n\tif d == _EMPTY_ {","sourceCodeStart":337,"sourceCodeEnd":373,"githubUrl":"https://github.com/nats-io/nats-server/blob/3a66a489d262bf89b71a71c955c94920394532f3/server/ocsp_responsecache.go#L337-L373","documentation":"This error wraps a failure to Close the s2 compression writer in LocalCache.Compress. s2 writers buffer data and only flush the final compressed block on Close, so a Close error means the compressed output is incomplete/unusable. The library refuses to return bytes that could be a corrupt cache entry.","triggerScenarios":"LocalCache.Put -> Compress where s2.Writer.Close() returns a non-nil error, typically because an underlying write to the bytes.Buffer failed or internal s2 state is inconsistent.","commonSituations":"Underlying writer failure while flushing the final block; calling Close twice or using the writer after Close; panics/OOM inside the compressor surfaced at Close.","solutions":["Check the error returned by writer.Close() and discard output.Bytes() — do not cache partial output.","Ensure Close is called exactly once per writer and after all writes complete.","Retry the compression of the same body once; s2 over bytes.Buffer should be deterministic.","If reproducible, update/replace the s2 library version or disable compression for this entry."],"exampleFix":"// before\nif err := writer.Close(); err != nil {\n\treturn nil, fmt.Errorf(certidp.ErrCannotCloseWriter, err)\n}\n// after\nif err := writer.Close(); err != nil {\n\treturn nil, fmt.Errorf(\"error closing compression writer: %w (discarding %d compressed bytes)\", err, output.Len())\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"compressed, err := cache.Compress(body)\nif err != nil {\n\tvar trunc *certidp.ErrTruncatedWrite\n\tswitch {\n\tcase errors.As(err, &trunc):\n\t\t// discard partial output, retry once\n\tdefault:\n\t\tlog.Printf(\"compress failed: %v\", err)\n\t}\n\treturn err\n}","preventionTips":["Call s2 writer Close exactly once, after all writes.","Check Close's error before trusting output.Bytes().","Retry deterministic compression once on transient failure."],"tags":["compression","io","cache","ocsp"],"backgroundTag":"writer-close-failed","analyzedSha":"3a66a489d262bf89b71a71c955c94920394532f3","analyzedAt":"2026-09-02T04:41:54.247Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}