nats-io/nats-server · error

RTT threshold values %v should be in ascending order

Error message

RTT threshold values %v should be in ascending order

What it means

When validating a server/compression Options RTTThresholds list, each non-zero threshold must appear in ascending order — they map RTT ranges to compression levels. If a newly provided value is smaller than any previously accepted threshold, the configuration is invalid and server Options validation fails.

Source

Thrown at server/server.go:518

	case "accept":
		c.Mode = CompressionAccept
	case "auto", "s2_auto":
		var rtts []time.Duration
		if len(c.RTTThresholds) == 0 {
			rtts = defaultCompressionS2AutoRTTThresholds
		} else {
			for _, n := range c.RTTThresholds {
				// Do not error on negative, but simply set to 0
				if n < 0 {
					n = 0
				}
				// Make sure they are properly ordered. However, it is possible
				// to have a "0" anywhere in the list to indicate that this
				// compression level should not be used.
				if l := len(rtts); l > 0 && n != 0 {
					for _, v := range rtts {
						if n < v {
							return fmt.Errorf("RTT threshold values %v should be in ascending order", c.RTTThresholds)
						}
					}
				}
				rtts = append(rtts, n)
			}
			if len(rtts) > 0 {
				// Trim 0 that are at the end.
				stop := -1
				for i := len(rtts) - 1; i >= 0; i-- {
					if rtts[i] != 0 {
						stop = i
						break
					}
				}
				rtts = rtts[:stop+1]
			}
			if len(rtts) > 4 {
				// There should be at most values for "uncompressed", "fast",

View on GitHub (pinned to 3a66a489d2)

Solutions

  1. Sort RTTThresholds ascending before applying Options
  2. Keep 0 entries anywhere (they disable a level) but ensure all non-zero values increase monotonically
  3. Build the slice from a sorted structure, not a map
  4. Validate the config in CI before deploying

Example fix

// before
c.RTTThresholds = []int64{300, 100, 200}
// after
thresholds := []int64{300, 100, 200}
thresholds = append([]int64{0}, thresholds...) // placeholder
sort.Slice(thresholds, func(i, j int) bool { return thresholds[i] < thresholds[j] })
c.RTTThresholds = thresholds
Defensive patterns

Strategy: validation

Validate before calling

// Go: validate RTTThresholds ordering before applying Options
func validRTTThresholds(t []int64) bool {
    prev := int64(0)
    for _, v := range t {
        if v != 0 {
            if prev != 0 && v < prev {
                return false
            }
            prev = v
        }
    }
    return true
}

Prevention

When it happens

Trigger: Setting Options.RTTThresholds (compression mode thresholds) to something like [200, 100, 300] — a later non-zero value smaller than an earlier one.

Common situations: Hand-editing config files and reordering thresholds, programmatically building the slice from an unordered map (Go map iteration order is random), or merging configs from different sources.

Related errors


AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02). Data as JSON: /api/errors/61d7ebe03da31058. Report an issue: GitHub.