{"record":{"id":"4ac63bee5252c2ad","repo":"nats-io/nats-server","slug":"unable-to-seal-data-v","errorCode":null,"errorMessage":"unable to seal data: %v","messagePattern":"unable to seal data: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"server/tpm/js_ek_tpm_windows.go","lineNumber":167,"sourceCode":"\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"unable to get policy: %v\", err)\n\t}\n\tif err := tpm2.FlushContext(rwc, sessHandle); err != nil {\n\t\treturn \"\", fmt.Errorf(\"unable to flush session: %v\", err)\n\t}\n\t// Seal the data to the parent key and the policy\n\tuser, err := nkeys.CreateUser()\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"unable to create seed: %v\", err)\n\t}\n\t// We'll use the seed to represent the encryption key.\n\tjsStoreKey, err := user.Seed()\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"unable to get seed: %v\", err)\n\t}\n\tprivateArea, publicArea, err := tpm2.Seal(rwc, srkHandle, srkPassword, jsKeyPassword, policy, jsStoreKey)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"unable to seal data: %v\", err)\n\t}\n\terr = writeTPMKeysToFile(jsKeyFile, privateArea, publicArea)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"unable to write key file: %v\", err)\n\t}\n\treturn string(jsStoreKey), nil\n}\n\n// Unseals the JetStream encryption key from the TPM with the provided keys.\n// The key is returned as a string.\nfunc unsealJsEncrpytionKey(rwc io.ReadWriteCloser, pcr int, srkHandle tpmutil.Handle, srkPassword, objectPassword string, publicBlob, privateBlob []byte) (string, error) {\n\t// Load the public/private blobs into the TPM for decryption.\n\tobjectHandle, _, err := tpm2.Load(rwc, srkHandle, srkPassword, publicBlob, privateBlob)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"unable to load data: %v\", err)\n\t}\n\tdefer tpm2.FlushContext(rwc, objectHandle)\n","sourceCodeStart":149,"sourceCodeEnd":185,"githubUrl":"https://github.com/nats-io/nats-server/blob/3a66a489d262bf89b71a71c955c94920394532f3/server/tpm/js_ek_tpm_windows.go#L149-L185","documentation":"createAndSealJsEncryptionKey failed to seal the newly generated JetStream encryption key into the TPM. tpm2.Seal wraps jsStoreKey under the SRK with a policy-PCR+password session; any TPM-level failure (handle, auth, policy mismatch) surfaces here wrapped with the underlying cause in %v.","triggerScenarios":"tpm2.Seal(rwc, srkHandle, srkPassword, jsKeyPassword, policy, jsStoreKey) returns non-nil err — e.g. bad SRK handle/password, SRK not created, policy digest mismatch, or TPM device I/O error.","commonSituations":"Wrong srkHandle or srkPassword passed in; TPM not accessible or not initialized; PCR state changed so the policy session is invalid; first run where the SRK persistent handle doesn't exist.","solutions":["Inspect the wrapped %v cause for the actual TPM error (auth failure vs I/O).","Verify the SRK handle (e.g. tpm2.HandleOwner) exists and srkPassword is correct (often empty string).","Confirm the TPM device is open and responsive before calling (see LoadJetStreamEncryptionKeyFromTPM).","Ensure the policy session (policyPCRPasswordSession) succeeds and PCRs haven't changed since sealing."],"exampleFix":"// before: guessing srk password\nprivateArea, publicArea, err := tpm2.Seal(rwc, srkHandle, srkPassword, jsKeyPassword, policy, jsStoreKey)\n// after: ensure SRK exists with empty auth before sealing\nsrkHandle := tpm2.HandleOwner\nsrkPassword := \"\" // default SRK auth unless changed\nprivateArea, publicArea, err := tpm2.Seal(rwc, srkHandle, srkPassword, jsKeyPassword, policy, jsStoreKey)","handlingStrategy":"try-catch","validationCode":"f, err := os.OpenFile(tpmDevicePath, os.O_RDWR, 0)\nif err != nil {\n\treturn fmt.Errorf(\"TPM device unavailable: %w\", err)\n}\nf.Close()","typeGuard":"func isTPMSealError(err error) bool {\n\treturn err != nil && strings.Contains(err.Error(), \"unable to seal data\")\n}","tryCatchPattern":"key, err := LoadJetStreamEncryptionKeyFromTPM(rwc)\nif err != nil {\n\tif strings.Contains(err.Error(), \"unable to seal data\") {\n\t\tlog.Printf(\"TPM seal failed: %v — verify SRK handle and PCR state\", err)\n\t}\n\treturn err\n}","preventionTips":["Verify the SRK persistent handle exists before sealing.","Keep srkPassword consistent (usually empty) across seal and unseal.","Test TPM connectivity at startup with a trivial TPM2_GetCapability call.","Log the wrapped cause verbatim for diagnosis."],"tags":["tpm","windows","jetstream","key-sealing","go"],"backgroundTag":"tpm-seal-failed","analyzedSha":"3a66a489d262bf89b71a71c955c94920394532f3","analyzedAt":"2026-09-02T04:41:54.247Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}