nats-io/nats-server · warning

%v unable to flush session: %v

Error message

%v
unable to flush session: %v

What it means

Not an independent throw site: it is the deferred cleanup in policyPCRPasswordSession that augments an existing error when flushing the auth session fails during error unwinding. The message is '%v\nunable to flush session: %v' — the original error plus the flush failure.

Source

Thrown at server/tpm/js_ek_tpm_windows.go:219

// 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*/
		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)
	}
	defer func() {
		if sessHandle != tpm2.HandleNull && err != nil {
			if err := tpm2.FlushContext(rwc, sessHandle); err != nil {
				retErr = fmt.Errorf("%v\nunable to flush session: %v", retErr, 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)
	}
	if err := tpm2.PolicyPassword(rwc, sessHandle); err != nil {
		return sessHandle, nil, fmt.Errorf("unable to require password for auth policy: %v", err)
	}
	policy, err = tpm2.PolicyGetDigest(rwc, sessHandle)
	if err != nil {
		return sessHandle, nil, fmt.Errorf("unable to get policy digest: %v", err)
	}

View on GitHub (pinned to 3a66a489d2)

Solutions

  1. Focus on the FIRST line of the error (the original cause); the flush failure is secondary.
  2. Ensure the rwc connection stays open until policyPCRPasswordSession returns.
  3. If flush errors recur, check TPM health/reset the device.
Defensive patterns

Strategy: try-catch

Try / catch

_, _, err := policyPCRPasswordSession(rwc, pcr)
if err != nil {
	lines := strings.SplitN(err.Error(), "\n", 2)
	log.Printf("primary error: %s", lines[0]) // flush failure (if any) is line 2
}

Prevention

When it happens

Trigger: An earlier step (PolicyPCR, PolicyPassword, PolicyGetDigest) failed AND the deferred tpm2.FlushContext on the still-open sessHandle also failed.

Common situations: TPM became unresponsive mid-operation; connection closed before deferred cleanup ran; rare, secondary failure masking attention from the primary error.

Related errors


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