nats-io/nats-server · error

JetStream encryption key may not be used with TPM options

Error message

JetStream encryption key may not be used with TPM options

What it means

initJetStreamEncryption rejects configs that set both a direct JetStream encryption key and TPM-based key sealing, because the two key sources are mutually exclusive — the server cannot decide whether to use the provided key or a TPM-sealed one.

Source

Thrown at server/jetstream.go:403

				if err := os.Rename(old, new); err != nil {
					return err
				}
			}
		}
	}

	return nil
}

// This function sets/updates the jetstream encryption key and cipher based
// on options. If the TPM options have been specified, a key is generated
// and sealed by the TPM.
func (s *Server) initJetStreamEncryption() (err error) {
	opts := s.getOpts()

	// The TPM settings and other encryption settings are mutually exclusive.
	if opts.JetStreamKey != _EMPTY_ && opts.JetStreamTpm.KeysFile != _EMPTY_ {
		return fmt.Errorf("JetStream encryption key may not be used with TPM options")
	}
	// if we are using the standard method to set the encryption key just return and carry on.
	if opts.JetStreamKey != _EMPTY_ {
		return nil
	}
	// if the tpm options are not used then no encryption has been configured and return.
	if opts.JetStreamTpm.KeysFile == _EMPTY_ {
		return nil
	}

	if opts.JetStreamTpm.Pcr == 0 {
		// Default PCR to use in the TPM. Values can be 0-23, and most platforms
		// reserve values 0-12 for the OS, boot locker, disc encryption, etc.
		// 16 used for debugging. In sticking to NATS tradition, we'll use 22
		// as the default with the option being configurable.
		opts.JetStreamTpm.Pcr = 22
	}

View on GitHub (pinned to 3a66a489d2)

Solutions

  1. Remove the JetStreamKey option and keep only the TPM settings, or vice versa
  2. Audit the final merged config/flags to ensure only one key source is set
  3. If TPM is desired, delete the plain key; if a plain key is desired, remove the jetstream tpm block

Example fix

// before
jetstream {
  key: "my-secret-key"
  tpm { keys_file: "/etc/nats/tpm-keys" }
}
// after
jetstream {
  tpm { keys_file: "/etc/nats/tpm-keys" }
}
Defensive patterns

Strategy: validation

Validate before calling

// Pre-validate options before EnableJetStream
if opts.JetStreamKey != "" && opts.JetStreamTpm.KeysFile != "" {
    return fmt.Errorf("set either jetstream key or tpm keys_file, not both")
}

Prevention

When it happens

Trigger: Server options include both a non-empty JetStreamKey (e.g. via --jetstream_key or JetStreamKey in config) and a non-empty JetStreamTpm.KeysFile (TPM keys file). Returned from EnableJetStream startup path.

Common situations: Merging config fragments where one sets jetstream key and another sets tpm block; leftover flag from a previous setup combined with new TPM config; automation templates writing both options.

Related errors


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