nats-io/nats-server · error

can not unmarshal

Error message

can not unmarshal %q

What it means

RetentionPolicy.UnmarshalJSON accepts only the exact JSON strings for LimitsPolicy, InterestPolicy, and WorkQueuePolicy (case-sensitive, exact match on the raw bytes). Any other JSON input, including misspellings or different casing, hits the default branch and returns this error.

Solutions

  1. Correct the JSON value to one of the exact strings: "limits", "interest", or "workqueue" (lowercase, quoted).
  2. Pre-validate incoming JSON against the allowed values before unmarshaling.
  3. Regenerate the config file using a matching version of nats-streaming-server.

Example fix

// before
var rp stan.RetentionPolicy
json.Unmarshal([]byte(`"limits_policy"`), &rp) // error
// after
json.Unmarshal([]byte(`"limits"`), &rp) // ok
Defensive patterns

Strategy: validation

Validate before calling

var allowedRetention = map[string]bool{"\"limits\"": true, "\"interest\"": true, "\"workqueue\"": true}
if !allowedRetention[string(data)] {
	return fmt.Errorf("invalid retention policy %s", data)
}

Type guard

func parseRetentionPolicy(data []byte) (stan.RetentionPolicy, bool) {
	var rp stan.RetentionPolicy
	if err := rp.UnmarshalJSON(data); err != nil {
		return 0, false
	}
	return rp, true
}

Try / catch

if err := json.Unmarshal(data, &rp); err != nil {
	if strings.Contains(err.Error(), "can not unmarshal") {
		log.Printf("unknown retention policy %q, defaulting to limits", data)
		rp = stan.LimitsPolicy
		return nil
	}
	return err
}

Prevention

When it happens

Trigger: json.Unmarshal (or loading a channel config file / obtaining a Channel via the store) where the retention field contains a value other than "limits", "interest", or "workqueue" exactly.

Common situations: Hand-edited or generated stan.conf with e.g. "Limits" or "limit" instead of "limits"; config written by a different/older server version using other tokens; programmatically unmarshaling user-supplied JSON.

Related errors


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

Appendix: source

Thrown at server/store.go:594

	case InterestPolicy:
		return interestPolicyJSONBytes, nil
	case WorkQueuePolicy:
		return workQueuePolicyJSONBytes, nil
	default:
		return nil, fmt.Errorf("can not marshal %v", rp)
	}
}

func (rp *RetentionPolicy) UnmarshalJSON(data []byte) error {
	switch string(data) {
	case limitsPolicyJSONString:
		*rp = LimitsPolicy
	case interestPolicyJSONString:
		*rp = InterestPolicy
	case workQueuePolicyJSONString:
		*rp = WorkQueuePolicy
	default:
		return fmt.Errorf("can not unmarshal %q", data)
	}
	return nil
}

func (dp DiscardPolicy) String() string {
	switch dp {
	case DiscardOld:
		return "DiscardOld"
	case DiscardNew:
		return "DiscardNew"
	default:
		return "Unknown Discard Policy"
	}
}

func (dp DiscardPolicy) MarshalJSON() ([]byte, error) {
	switch dp {
	case DiscardOld:

View on GitHub (pinned to 3a66a489d2)