nats-io/nats-server · error
unable to get auth session: %v
Error message
unable to get auth session: %v
What it means
unsealJsEncrpytionKey could not create the policy PCR+password authorization session via policyPCRPasswordSession. The wrapped error from StartAuthSession (or later policy commands) is embedded in %v.
Source
Thrown at server/tpm/js_ek_tpm_windows.go:189
return "", fmt.Errorf("unable to write key file: %v", err)
}
return string(jsStoreKey), nil
}
// Unseals the JetStream encryption key from the TPM with the provided keys.
// The key is returned as a string.
func unsealJsEncrpytionKey(rwc io.ReadWriteCloser, pcr int, srkHandle tpmutil.Handle, srkPassword, objectPassword string, publicBlob, privateBlob []byte) (string, error) {
// Load the public/private blobs into the TPM for decryption.
objectHandle, _, err := tpm2.Load(rwc, srkHandle, srkPassword, publicBlob, privateBlob)
if err != nil {
return "", fmt.Errorf("unable to load data: %v", err)
}
defer tpm2.FlushContext(rwc, objectHandle)
// Create the authorization session with TPM.
sessHandle, _, err := policyPCRPasswordSession(rwc, pcr)
if err != nil {
return "", fmt.Errorf("unable to get auth session: %v", err)
}
defer func() {
tpm2.FlushContext(rwc, sessHandle)
}()
// Unseal the data we've loaded into the TPM with the object (js key) password.
unsealedData, err := tpm2.UnsealWithSession(rwc, sessHandle, objectHandle, objectPassword)
if err != nil {
return "", fmt.Errorf("unable to unseal data: %v", err)
}
return string(unsealedData), nil
}
// Returns session handle and policy digest.
func policyPCRPasswordSession(rwc io.ReadWriteCloser, pcr int) (sessHandle tpmutil.Handle, policy []byte, retErr error) {
sessHandle, _, err := tpm2.StartAuthSession(
rwc,
tpm2.HandleNull, /*tpmKey*/
tpm2.HandleNull, /*bindKey*/View on GitHub (pinned to 3a66a489d2)
Solutions
- Check the embedded %v cause from StartAuthSession.
- Validate the configured pcr index is a valid SHA-256 PCR (0-23 on typical TPMs).
- Restart the process/host to clear leaked sessions if the session table is full.
- Confirm the TPM device is healthy (run tpm2_getcap or vendor diagnostics).
Example fix
// before: unchecked PCR value
key, err := unsealJsEncrpytionKey(rwc, pcr, srkHandle, ...)
// after: validate pcr config first
if pcr < 0 || pcr > 23 {
return "", fmt.Errorf("invalid PCR index %d", pcr)
}
key, err := unsealJsEncrpytionKey(rwc, pcr, srkHandle, ...) Defensive patterns
Strategy: retry
Validate before calling
if pcr < 0 || pcr > 23 {
return fmt.Errorf("invalid PCR index %d", pcr)
}
if _, err := tpm2.ReadPCRs(rwc, tpm2.PCRSelection{Hash: tpm2.AlgSHA256, PCRs: []int{pcr}}); err != nil {
return fmt.Errorf("PCR %d not readable: %w", pcr, err)
} Try / catch
var key string
var err error
for i := 0; i < 3; i++ {
key, err = LoadJetStreamEncryptionKeyFromTPM(rwc)
if err == nil || !strings.Contains(err.Error(), "unable to get auth session") {
break
}
time.Sleep(200 * time.Millisecond)
} Prevention
- Validate the configured PCR index against the TPM's PCR capabilities.
- Limit concurrent TPM users to avoid session table exhaustion.
- Always FlushContext for every started session.
- Monitor TPM health at startup.
When it happens
Trigger: policyPCRPasswordSession(rwc, pcr) returns error — TPM auth session limit reached, invalid PCR index, or TPM communication failure.
Common situations: Invalid pcr value configured (out of range for the PCR bank); TPM session table full from leaked sessions; TPM device in a failed/locked state.
Related errors
- unable to unseal data: %v
- unable to start session: %v
- unable to bind PCRs to auth policy: %v
- unable to seal data: %v
- unable to write key file: %v
AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02).
Data as JSON: /api/errors/97ef654110572481.
Report an issue: GitHub.