v2.12.9

nats-io/nats-serverv2.12.9May 20, 2026by github-actions[bot]

AI Summary

A maintenance release for the 2.12 branch focusing on JetStream stability, performance optimizations, and dependency updates. It shares many JetStream fixes and improvements with the v2.14.1 release.

Key Highlights

  • New monitoring metrics for tracking data to/from normal clients
  • Improved JetStream performance metrics calculation and reduced lock contention
  • Fixed various protocol errors, Raft stability issues, and memory leaks
  • Updated Go version to 1.25.10

Full Release Notes

## Changelog

Refer to the [2.12 Upgrade Guide](https://docs.nats.io/release-notes/whats_new/whats_new_212) for backwards compatibility notes with 2.11.x.

### Go Version

- 1.25.10 (#8107)

### Dependencies

- github.com/klauspost/compress v1.18.6 (#8124)
- golang.org/x/crypto v0.51.0 (#8124)
- golang.org/x/sys v0.44.0 (#8124)

### Added

General

- New metrics `in_client_msgs`, `in_client_bytes`, `out_client_msgs` and `out_client_bytes` are now available via the `/varz` monitoring endpoint for tracking data to/from normal clients only (#7851)

### Improved

General

- Client TLS certificates without subject DNs but with DNS subject alternate names are now permitted (#8100)
- The log level of TLS handshake timeout or non-TLS record errors have been demoted to debug level to reduce noise (#8096)

JetStream

- Num pending is now only calculated on consumer leaders, avoiding unnecessary CPU usage on followers (#8172)
- Snapshot and catchup loops no longer leak timers (#8186, thanks to @SebTardif)
- Stream and consumer assignment errors are now surfaced (#8208)
- Intersection of sublists and subject trees can now be cancelled early, avoiding high CPU usage in some pathological cases (#8209)

### Fixed

General

- Fixed a deadlock that could occur when processing cluster info hit Raft lock contention (#8080)
- A number of sublists that incorrectly ignored the `disable_sublist_cache` option have been fixed (#8081)
- Cluster route compression now obeys the cluster `max_pings_out` option if configured (#8093)
- The internal send loop no longer mutates caller headers, which could corrupt buffers (#8097)
- Removing headers no longer fails to remove later headers if the matching prefix also appeared in an earlier header value (#8103)
- The sublist now correctly maintains negative results in the cache when calculating number of interested subjects (#8119)
- Server shutdown requests are now idempotent, preventing concurrency issues when shutting down in embedded contexts (#8163)
- TLS listeners now work correctly with the PROXY protocol where enabled (#8130)
- Reduced lock contention that could be created between leafnodes and clients (#8139, #8159)
- Fixed a panic that could happen when an error occurs when walking JWT directory resolver folders (#8173, thanks to @SebTardif)
- In-process connections will no longer unexpectedly revert to TLS required with async `INFO` (#8205)

Leafnodes

- Leafnode connections will no longer negotiate compression if they are configured over already-compressed WebSockets (#7969)

JetStream

- Atomic batch now sends an unsupported advisory on API level mismatch (#8082)
- A bug which corrupted message schedule subjects on recovery has been fixed (#8085)
- Reduced lock contention on node leader changes and Raft group creation (#8087)
- Fixed a protocol error that could be caused by double-encoding of `$JS.ACK` reply subjects over routes or gateways (#8089)
– Fixed a panic that could occur when decoding a truncated Raft append entry from the wire (#8092)
- Atomic batch no longer double-pools committed entries on cleanup (#8098)
- Raft nodes will now ignore temporary snapshots on recovery after a crash (#8101)
- A number of paths that could leave consumer redelivered in a drifted state have been fixed, e.g. with workqueue or interest-based streams with `max_deliver`, on single message removal or after purges/compactions (#8102)
- Caches are now cleared correctly when converting filestore encryption mode, avoiding block-level corruption (#8105, #8166)
- Fixed a race condition when updating the deduplication map on leader change (#8106)
- Source consumer creation will no longer schedule a recreation if a setup is already in progress, avoiding potential setup storms (#8111)
- Fixed data races when reading from the stream configuration when checking reservations, answering some API requests amongst others (#8115)
- Stream republish subjects are now validated correctly (#8127)
- The delivery policy for consumers on clustered workqueue streams is now enforced correctly (#8126)
- Raft node append entry caches are now invalidated correctly on WAL truncation and snapshot installs (#8149)
- Skip message errors are now surfaced correctly, propagating failures (#8152)
- Mirror consumers are now retried immediately on a last sequence mismatch, avoiding stalling for longer than necessary (#8152)
- Raft nodes will no longer allow proposals to remove unknown peers (#8154)
- Pending state no longer leaks when reaching max deliveries (#8156)
- A panic when reusing a wait group when resetting a stream's clustered state has been fixed (#8158)
- Correctly reset local meta log when extending the meta group to a parent domain (#8142)
- Consumer file stores will now correctly flush when deleting a single redelivery, avoiding unexpected further redeliveries (#8168)
- Storage reservations for un-tiered streams have been made consistent between creates/updates and clustered/non-clustered modes (#8170)
- Raft will now correctly cancel an in-flight checkpoint operation when resetting (#8180, #8202)
- The `JetStreamMaxMemory` and `JetStreamMaxStore` options are now handled correctly in embedded mode (#8184)
- A number of fields that were aliasing underlying filestore block caches have been fixed (#8187)
- Consumers with `inactive_threshold` should no longer have their local state deleted unexpectedly when the proposal to the metalayer to clean up the consumer fails (#8198)
- Metalayer state is now preserved in a number of cases where it was incorrectly being removed on shutdown (#8199)

MQTT

- Invalid characters in subjects are now rejected correctly, avoiding protocol issues when forwarded to other connection types (#8104, #8112)

### Complete Changes
 
https://github.com/nats-io/nats-server/compare/v2.12.8...v2.12.9