{"record":{"id":"562a8a327e24114b","repo":"nats-io/nats-server","slug":"unable-to-get-policy-digest-v","errorCode":null,"errorMessage":"unable to get policy digest: %v","messagePattern":"unable to get policy digest: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/tpm/js_ek_tpm_windows.go","lineNumber":236,"sourceCode":"\t\t\tif err := tpm2.FlushContext(rwc, sessHandle); err != nil {\n\t\t\t\tretErr = fmt.Errorf(\"%v\\nunable to flush session: %v\", retErr, err)\n\t\t\t}\n\t\t}\n\t}()\n\n\tpcrSelection := tpm2.PCRSelection{\n\t\tHash: tpm2.AlgSHA256,\n\t\tPCRs: []int{pcr},\n\t}\n\tif err := tpm2.PolicyPCR(rwc, sessHandle, nil, pcrSelection); err != nil {\n\t\treturn sessHandle, nil, fmt.Errorf(\"unable to bind PCRs to auth policy: %v\", err)\n\t}\n\tif err := tpm2.PolicyPassword(rwc, sessHandle); err != nil {\n\t\treturn sessHandle, nil, fmt.Errorf(\"unable to require password for auth policy: %v\", err)\n\t}\n\tpolicy, err = tpm2.PolicyGetDigest(rwc, sessHandle)\n\tif err != nil {\n\t\treturn sessHandle, nil, fmt.Errorf(\"unable to get policy digest: %v\", err)\n\t}\n\treturn sessHandle, policy, nil\n}\n\n// LoadJetStreamEncryptionKeyFromTPM loads the JetStream encryption key from the TPM.\n// If the keyfile does not exist, a key will be created and sealed. Public and private blobs\n// used to decrypt the key in future sessions will be saved to disk in the file provided.\n// The key will be unsealed and returned only with the correct password and PCR value.\nfunc LoadJetStreamEncryptionKeyFromTPM(srkPassword, jsKeyFile, jsKeyPassword string, pcr int) (string, error) {\n\trwc, err := tpm2.OpenTPM()\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"could not open the TPM: %v\", err)\n\t}\n\tdefer rwc.Close()\n\n\t// Load the key from the TPM\n\tsrkHandle, err := regenerateSRK(rwc, srkPassword)\n\tdefer func() {","sourceCodeStart":218,"sourceCodeEnd":254,"githubUrl":"https://github.com/nats-io/nats-server/blob/3a66a489d262bf89b71a71c955c94920394532f3/server/tpm/js_ek_tpm_windows.go#L218-L254","documentation":"policyPCRPasswordSession could not retrieve the final policy digest via tpm2.PolicyGetDigest after binding PCR and password checks. This digest is required for the subsequent Seal operation, so the whole session is abandoned.","triggerScenarios":"tpm2.PolicyGetDigest(rwc, sessHandle) errors — invalid session handle or TPM I/O failure after the earlier policy commands succeeded.","commonSituations":"Connection dropped between policy commands and digest retrieval; session flushed by a concurrent TPM user; TPM device error.","solutions":["Check the embedded %v cause for the TPM return code.","Ensure no other process/thread flushes the same session concurrently.","Retry the full policyPCRPasswordSession call.","Verify TPM device connectivity (rwc) is stable."],"exampleFix":"// before\ntp2policy, err = tpm2.PolicyGetDigest(rwc, sessHandle)\n// after: retry session as a unit on digest failure\npolicy, err = tpm2.PolicyGetDigest(rwc, sessHandle)\nif err != nil {\n\ttpm2.FlushContext(rwc, sessHandle)\n\treturn tpm2.HandleNull, nil, fmt.Errorf(\"unable to get policy digest: %v\", err)\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":"func isPolicyDigestError(err error) bool {\n\treturn err != nil && strings.Contains(err.Error(), \"unable to get policy digest\")\n}","tryCatchPattern":"sessHandle, policy, err := policyPCRPasswordSession(rwc, pcr)\nif err != nil && isPolicyDigestError(err) {\n\ttime.Sleep(200 * time.Millisecond)\n\tsessHandle, policy, err = policyPCRPasswordSession(rwc, pcr) // full retry\n}","preventionTips":["Always retry the whole policyPCRPasswordSession, not just PolicyGetDigest.","Ensure the rwc connection is stable (no mid-operation close).","Serialize TPM access to prevent other code from flushing your session.","Flush the session handle explicitly when abandoning a partial session."],"tags":["tpm","windows","policy","digest","go"],"backgroundTag":"tpm-policy-command-failed","analyzedSha":"3a66a489d262bf89b71a71c955c94920394532f3","analyzedAt":"2026-09-02T04:41:54.247Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}