nats-io/nats-server · error

can not marshal %v

Error message

can not marshal %v

What it means

PersistModeType.MarshalJSON returns this error when the PersistMode value being serialized is not DefaultPersistMode or AsyncPersistMode — i.e. the in-memory enum holds an out-of-range value. This surfaces when marshaling a stream config that carries a corrupted or uninitialized PersistMode.

Source

Thrown at server/stream.go:227

func (wc PersistModeType) String() string {
	switch wc {
	case DefaultPersistMode:
		return "Default"
	case AsyncPersistMode:
		return "Async"
	default:
		return "Unknown Persist Mode Type"
	}
}

func (wc PersistModeType) MarshalJSON() ([]byte, error) {
	switch wc {
	case DefaultPersistMode:
		return defaultPersistModeJSONBytes, nil
	case AsyncPersistMode:
		return asyncPersistModeJSONBytes, nil
	default:
		return nil, fmt.Errorf("can not marshal %v", wc)
	}
}

func (wc *PersistModeType) UnmarshalJSON(data []byte) error {
	switch string(data) {
	case defaultPersistModeJSONString, `""`:
		*wc = DefaultPersistMode
	case asyncPersistModeJSONString:
		*wc = AsyncPersistMode
	default:
		return fmt.Errorf("can not unmarshal %q", data)
	}
	return nil
}

// JSPubAckResponse is a formal response to a publish operation.
type JSPubAckResponse struct {
	Error *ApiError `json:"error,omitempty"`

View on GitHub (pinned to 3a66a489d2)

Solutions

  1. Set PersistMode only via the defined constants: DefaultPersistMode or AsyncPersistMode.
  2. Check for casts/assignments that put an arbitrary integer into the PersistMode field.
  3. If async persistence is intended, set the field explicitly to AsyncPersistMode; otherwise leave it DefaultPersistMode.

Example fix

// before
cfg := StreamConfig{PersistMode: PersistModeType(7)}
// after
cfg := StreamConfig{PersistMode: AsyncPersistMode}
Defensive patterns

Strategy: validation

Validate before calling

if wc := cfg.PersistMode; wc != DefaultPersistMode && wc != AsyncPersistMode {
  return fmt.Errorf("invalid persist mode %v", wc)
}

Type guard

func isPersistMode(w PersistModeType) bool {
  return w == DefaultPersistMode || w == AsyncPersistMode
}

Prevention

When it happens

Trigger: json.Marshal on a StreamConfig whose PersistMode field was set to an out-of-range value (e.g. constructed via an unchecked cast or zero-value outside the known constants).

Common situations: Custom tooling that builds StreamConfig structs programmatically, or older binaries writing configs consumed as raw ints.

Related errors


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