nats-io/nats-server · error

must be int64 or string

Error message

must be int64 or string

What it means

getStorageSize() in nats-server (server/opts.go:2495) parses a JetStream storage size that config may express as either an int64 (bytes) or a string with a size suffix. If the value is neither an int64 nor a string, the function returns 'must be int64 or string'. This protects against wrong-typed config values (e.g. YAML/JSON numbers decoded as float64 or bool).

Source

Thrown at server/opts.go:2503

			}
		}
		acc.jsLimits = map[string]JetStreamAccountLimits{_EMPTY_: jsLimits}
	default:
		return &configErr{tk, fmt.Sprintf("Expected map, bool or string to define JetStream, got %T", v)}
	}
	return nil
}

// takes in a storage size as either an int or a string and returns an int64 value based on the input.
func getStorageSize(v any) (int64, error) {
	_, ok := v.(int64)
	if ok {
		return v.(int64), nil
	}

	s, ok := v.(string)
	if !ok {
		return 0, fmt.Errorf("must be int64 or string")
	}

	if s == _EMPTY_ {
		return 0, nil
	}

	suffix := s[len(s)-1:]
	prefix := s[:len(s)-1]
	num, err := strconv.ParseInt(prefix, 10, 64)
	if err != nil {
		return 0, err
	}

	suffixMap := map[string]int64{"K": 10, "M": 20, "G": 30, "T": 40}

	mult, ok := suffixMap[suffix]
	if !ok {
		return 0, fmt.Errorf("sizes defined as strings must end in K, M, G, T")

View on GitHub (pinned to 3a66a489d2)

Solutions

  1. Convert the value to int64 (bytes) or a string like "1G" before passing it
  2. If the value comes from JSON/YAML generic decoding, convert float64 to int64 first (int64(v.(float64)))
  3. Check the config section producing the value and fix its type
  4. Upgrade/patch config parsing so numeric values are decoded as int64

Example fix

// before
limits["max_memory"] = 1024 // decoded as int or float64, not int64
// after
limits["max_memory"] = int64(1024)
// or as a string
limits["max_memory"] = "1K"
Defensive patterns

Strategy: type-guard

Validate before calling

func validStorageSize(v any) bool {
	switch t := v.(type) {
	case int64:
		return t >= 0
	case string:
		if t == "" { return true }
		s := t[:len(t)-1]
		_, err := strconv.ParseInt(s, 10, 64)
		return err == nil && strings.ContainsAny(t[len(t)-1:], "KMGT")
	}
	return false
}

Type guard

func asStorageSize(v any) (int64, bool) {
	switch t := v.(type) {
	case int64:
		return t, true
	case int:
		return int64(t), true
	case float64:
		return int64(t), true
	}
	return 0, false
}

Try / catch

if size, err := getStorageSize(v); err != nil {
	return fmt.Errorf("storage size invalid: %w", err)
}

Prevention

When it happens

Trigger: Passing a value of any type other than int64 or string to getStorageSize, e.g. a JSON number decoded as float64/float32, a bool, a map, or an int (not int64) in parsed config used for JetStream limits (parseJetStreamLimits path).

Common situations: Writing a size as a plain YAML/JSON number that decodes to float64 instead of int64; using an int literal in Go config-building code instead of int64; feeding config from a generic map[string]any without normalizing types.

Related errors


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