nats-io/nats-server · error
can not unmarshal %q
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.
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)
Solutions
- Correct the JSON value to one of the exact strings: "limits", "interest", or "workqueue" (lowercase, quoted).
- Pre-validate incoming JSON against the allowed values before unmarshaling.
- 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
- Keep config files lowercase and quoted exactly as the library constants define.
- Never hand-edit persisted state; use the server's own tooling.
- Add schema validation on any externally supplied JSON before unmarshaling.
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.