{"record":{"id":"785df33897b42698","repo":"nats-io/nats-server","slug":"error-writing-to-compression-writer-w-785df3","errorCode":null,"errorMessage":"error writing to compression writer: %w","messagePattern":"error writing to compression writer: %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/ocsp_responsecache.go","lineNumber":350,"sourceCode":"\tfor _, resp := range c.cache {\n\t\tswitch resp.RespStatus {\n\t\tcase ocsp.Good:\n\t\t\tc.stats.Goods++\n\t\tcase ocsp.Revoked:\n\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()","sourceCodeStart":332,"sourceCodeEnd":368,"githubUrl":"https://github.com/nats-io/nats-server/blob/3a66a489d262bf89b71a71c955c94920394532f3/server/ocsp_responsecache.go#L332-L368","documentation":"LocalCache.Compress compresses a cache entry with an s2.Writer. If io.CopyN into the writer fails, the error is wrapped with certidp.ErrCannotWriteCompressed (\"error writing to compression writer: %w\").","triggerScenarios":"Put() stores a response body and Compress's io.CopyN(writer, input, bodyLen) returns a non-nil error from the s2 writer writing to the underlying bytes.Buffer.","commonSituations":"Memory pressure/allocation failure in the s2 writer, pathological input causing writer errors, or a corrupted internal buffer state in the response cache.","solutions":["Retry the Put operation (transient failure)","Check host memory availability; s2 compression allocates buffers","Upgrade the NATS server / golang s2 library to pick up compression bug fixes"],"exampleFix":"// before\ncompressed, err := cache.Compress(buf)  // err surfaces from s2 writer\n// after\nif err != nil {\n    return fmt.Errorf(\"compressing cache entry failed: %w\", err) // retry Put\n}","handlingStrategy":"try-catch","validationCode":"if len(buf) == 0 { return errors.New(\"nothing to compress\") }","typeGuard":null,"tryCatchPattern":"compressed, err := cache.Compress(buf)\nif err != nil {\n    var we *s2.Writer // log and retry the Put\n    log.Printf(\"cache compress failed: %v; retrying\", err)\n    compressed, err = cache.Compress(buf)\n    if err != nil { return err }\n}","preventionTips":["Monitor host memory on nodes running the OCSP response cache","Keep the s2 dependency updated","Add retry logic around cache Put operations"],"tags":["compression","s2","ocsp-cache","io"],"backgroundTag":"compression-write-failed","analyzedSha":"3a66a489d262bf89b71a71c955c94920394532f3","analyzedAt":"2026-09-02T04:41:54.247Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}