nats-io/nats-server · error

unable to marshal keys to JSON: %v

Error message

unable to marshal keys to JSON: %v

What it means

writeTPMKeysToFile failed to serialize the natsTPMPersistedKeys struct (version plus base64-encoded private/public TPM blobs) to JSON before persisting the JetStream key file. In practice json.Marshal on this plain struct of strings/byte slices essentially never fails; if it does, it signals a programming error such as an unsupported field type, not a runtime or I/O problem.

Source

Thrown at server/tpm/js_ek_tpm_windows.go:104

tpmKeys := natsTPMPersistedKeys{
	Version:    JsKeyTPMVersion,
	PrivateKey: make([]byte, base64.StdEncoding.EncodedLen(len(privateBlob))),
	PublicKey:  make([]byte, base64.StdEncoding.EncodedLen(len(publicBlob))),
}
base64.StdEncoding.Encode(tpmKeys.PrivateKey, privateBlob)
base64.StdEncoding.Encode(tpmKeys.PublicKey, publicBlob)
// Convert to JSON
keysJSON, err := json.Marshal(tpmKeys)
if err != nil {
	return fmt.Errorf("unable to marshal keys to JSON: %v", err)
}
// Write the JSON to a file
if err := os.WriteFile(filename, keysJSON, 0640); err != nil {
	return fmt.Errorf("unable to write keys file to %q: %v", filename, err)
}
return nil

View on GitHub (pinned to 3a66a489d2)

Solutions

  1. Verify the natsTPMPersistedKeys struct only contains JSON-serializable types (version int, base64 byte slices)
  2. Retry the key creation; a transient marshal failure of a plain struct is practically impossible
  3. Inspect the wrapped error to confirm no embedded unsupported values (e.g. channels, funcs) were added to the struct
Defensive patterns

Strategy: fallback

When it happens

Trigger: Thrown at server/tpm/js_ek_tpm_windows.go:104 when the library encounters an invalid state.

Common situations: See trigger scenarios.


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