nats-io/nats-server · error
unable to start session: %v
Error message
unable to start session: %v
What it means
tpm2.StartAuthSession failed when policyPCRPasswordSession tried to open a policy session (SHA-256, unbound, salted-null) with the TPM. No authorization session exists, so neither sealing nor unsealing of the JetStream key can proceed. Common causes: TPM busy/out of session slots, device I/O errors, or unsupported session/algorithm combination.
Source
Thrown at server/tpm/js_ek_tpm_windows.go:214
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*/
make([]byte, 16), /*nonceCaller*/
nil, /*secret*/
tpm2.SessionPolicy,
tpm2.AlgNull,
tpm2.AlgSHA256)
if err != nil {
return tpm2.HandleNull, nil, fmt.Errorf("unable to start session: %v", err)
}
pcrSelection := tpm2.PCRSelection{
Hash: tpm2.AlgSHA256,
PCRs: []int{pcr},
}
if err := tpm2.PolicyPCR(rwc, sessHandle, nil, pcrSelection); err != nil {
return sessHandle, nil, fmt.Errorf("unable to bind PCRs to auth policy: %v", err)
}
return sessHandle, policy, nil
}View on GitHub (pinned to 3a66a489d2)
Solutions
- Check the wrapped TPM error for TPM_RC_SESSION_HANDLES exhaustion or I/O failure
- Close leaked sessions or reset the TPM if session slots are exhausted
- Verify the TPM device is accessible and supports policy sessions with SHA-256
- Retry the operation after the TPM recovers
Example fix
// before: session leaks accumulate
sessCreate, _, err := tpm2.StartAuthSession(...)
// after: always flush even on later failure (already done here) and cap concurrency
sem := make(chan struct{}, 1) // serialize TPM session usage
sem <- struct{}{}
sessCreate, _, err := tpm2.StartAuthSession(...) Defensive patterns
Strategy: retry
Validate before calling
if _, err := rwc.Write(nil); err != nil { // connection sanity probe
return fmt.Errorf("TPM connection dead: %w", err)
} Try / catch
sessHandle, policy, err := policyPCRPasswordSession(rwc, pcr)
if err != nil && strings.Contains(err.Error(), "unable to start session") {
time.Sleep(250 * time.Millisecond) // transient TPM busyness
sessHandle, policy, err = policyPCRPasswordSession(rwc, pcr)
} Prevention
- Serialize TPM access to avoid exhausting the session table.
- Audit code paths for sessions started without FlushContext.
- Open the TPM connection lazily, just before use.
- Reboot/reset the TPM if session exhaustion recurs.
When it happens
Trigger: tpm2.StartAuthSession(...) returns error — TPM session table exhausted, transient failures, or the device handle is invalid/closed.
Common situations: Too many concurrent TPM sessions (leaked sessions from prior errors); rwc closed before this call; TPM under heavy load or in a lockout state.
Related errors
- unable to get auth session: %v
- unable to seal data: %v
- unable to write key file: %v
- unable to load data: %v
- unable to unseal data: %v
AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02).
Data as JSON: /api/errors/62b51a64f8c748f2.
Report an issue: GitHub.