nats-io/nats-server · critical
unable to load data: %v
Error message
unable to load data: %v
What it means
unsealJsEncrpytionKey could not load the previously sealed key's public/private blobs back into the TPM. tpm2.Load re-imports the object under the SRK; failure typically means the blobs don't match the current SRK or are corrupted.
Source
Thrown at server/tpm/js_ek_tpm_windows.go:182
}
privateArea, publicArea, err := tpm2.Seal(rwc, srkHandle, srkPassword, jsKeyPassword, policy, jsStoreKey)
if err != nil {
return "", fmt.Errorf("unable to seal data: %v", err)
}
err = writeTPMKeysToFile(jsKeyFile, privateArea, publicArea)
if err != nil {
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
}View on GitHub (pinned to 3a66a489d2)
Solutions
- Delete the stale key file and let LoadJetStreamEncryptionKeyFromTPM recreate the key.
- Verify the key file was created on the SAME TPM (sealed blobs are not portable).
- Confirm srkHandle/srkPassword match those used at seal time.
- Check the blobs were not swapped or truncated when written/read.
Example fix
// before: blindly loading stale blobs
objectHandle, _, err := tpm2.Load(rwc, srkHandle, srkPassword, publicBlob, privateBlob)
if err != nil {
return "", fmt.Errorf("unable to load data: %v", err)
}
// after: caller fallback — remove key file and re-create on mismatch
if _, err := tpm2.Load(rwc, srkHandle, srkPassword, publicBlob, privateBlob); err != nil {
os.Remove(jsKeyFile) // force re-seal path
return LoadJetStreamEncryptionKeyFromTPM(...)
} Defensive patterns
Strategy: fallback
Validate before calling
info, err := os.Stat(jsKeyFile)
if err != nil || info.Size() == 0 {
// force re-seal path
os.Remove(jsKeyFile)
} Type guard
func isTPMLoadError(err error) bool {
return err != nil && strings.Contains(err.Error(), "unable to load data")
} Try / catch
key, err := LoadJetStreamEncryptionKeyFromTPM(rwc)
if err != nil && isTPMLoadError(err) {
os.Remove(jsKeyFile) // blobs unusable on this TPM; regenerate
key, err = LoadJetStreamEncryptionKeyFromTPM(rwc)
} Prevention
- Never copy TPM key files between machines — blobs are TPM-bound.
- Detect corrupt/oversized/zero-length key files at startup.
- Record which TPM/host created the key file.
- Note that deleting the key file invalidates previously encrypted data.
When it happens
Trigger: tpm2.Load(rwc, srkHandle, srkPassword, publicBlob, privateBlob) errors — blobs corrupted/truncated, key file from a different machine/TPM, wrong srkHandle, or wrong srkPassword.
Common situations: Copying the key file between machines (TPM-sealed data is TPM-specific); key file truncated by a bad write; TPM was re-provisioned so the SRK changed; swapping private and public blobs.
Related errors
- unable to seal data: %v
- unable to write key file: %v
- unable to get auth session: %v
- unable to unseal data: %v
- unable to start session: %v
AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02).
Data as JSON: /api/errors/ce269a3da3b11326.
Report an issue: GitHub.