{"record":{"id":"095db5dd2d1a76c2","repo":"hashicorp/nomad","slug":"could-not-load-key-file-s-from-keystore-w","errorCode":null,"errorMessage":"could not load key file %s from keystore: %w","messagePattern":"could not load key file (.+?) from keystore: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"nomad/encrypter.go","lineNumber":186,"sourceCode":"\t\tif !strings.HasSuffix(path, nomadKeystoreExtension) {\n\t\t\treturn nil\n\t\t}\n\t\tidWithIndex := strings.TrimSuffix(filepath.Base(path), nomadKeystoreExtension)\n\t\tid, _, _ := strings.Cut(idWithIndex, \".\")\n\t\tif !helper.IsUUID(id) {\n\t\t\treturn nil\n\t\t}\n\n\t\te.keyringLock.RLock()\n\t\t_, ok := e.keyring[id]\n\t\te.keyringLock.RUnlock()\n\t\tif ok {\n\t\t\treturn nil // already loaded this key from another file\n\t\t}\n\n\t\tkey, err := e.loadKeyFromStore(path)\n\t\tif err != nil {\n\t\t\tkeyErrors[id] = fmt.Errorf(\"could not load key file %s from keystore: %w\", path, err)\n\t\t\treturn nil\n\t\t}\n\t\tif key.Meta.KeyID != id {\n\t\t\treturn fmt.Errorf(\"root key ID %s must match key file %s\", key.Meta.KeyID, path)\n\t\t}\n\n\t\terr = e.addCipher(key)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"could not add key file %s to keystore: %w\", path, err)\n\t\t}\n\n\t\t// we loaded this key from at least one KEK configuration, so clear any\n\t\t// error from a previous file that we couldn't read from\n\t\tdelete(keyErrors, id)\n\t\treturn nil\n\t})\n\n\tif len(keyErrors) == 0 {","sourceCodeStart":168,"sourceCodeEnd":204,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/encrypter.go#L168-L204","documentation":"During keystore load (loadKeyFromStore path), a key file on disk for root key ID <id> could not be read/parsed. The underlying error from loadKeyFromStore (file IO, JSON decode, key unmarshal) is wrapped and stored per key ID; Nomad continues loading other files but will fail keyring init if no file for that key succeeds.","triggerScenarios":"NewEncrypter -> loadKeystore iterates .nks.json files in the keystore directory and calls loadKeyFromStore(path); any IO error (missing file, permissions), JSON parse error, or structs.RootKey decode error for the key matching id produces this error.","commonSituations":"Keystore directory partially restored from backup, wrong file permissions after running the agent as a different user, manually edited/corrupted key file JSON, stale symlink, or disk issue on the data dir.","solutions":["Read the wrapped cause (%w) in the agent log to identify whether it is IO, permissions, or JSON decode","Fix file permissions/ownership on the keystore file (should be readable only by the nomad user)","Restore the key file from a backup or from another server's keystore directory","If the key is intentionally retired, remove its keyring metadata and the corrupt file together (after rotation) so the loader stops looking for it"],"exampleFix":"// before: key file unreadable\n$ ls -l data/keystore/*.nks.json\n-rw------- 1 root root ... abc.nks.json   (nomad runs as 'nomad' user)\n// after\n$ chown nomad:nomad data/keystore/abc.nks.json && chmod 600 data/keystore/abc.nks.json","handlingStrategy":"validation","validationCode":"// before starting the agent, sanity-check keystore files\nimport \"os\"\nfunc checkKeystore(dir string) error {\n  files, err := filepath.Glob(filepath.Join(dir, \"*.nks.json\"))\n  if err != nil { return err }\n  for _, f := range files {\n    if fi, err := os.Stat(f); err != nil || fi.Size() == 0 {\n      return fmt.Errorf(\"keystore file %s missing or empty: %w\", f, err)\n    }\n  }\n  return nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Back up the keystore directory with consistent snapshots (metadata + key files together)","Run the nomad agent as a dedicated user and keep keystore files 0600 owned by it","Never hand-edit or rename .nks.json files","Monitor agent logs at startup for keyring load warnings"],"tags":["keyring","keystore","file-io","go"],"backgroundTag":"keystore-key-file-unreadable","analyzedSha":"482b49bf1aec006f089bcfc7e632d8f6ac303e5e","analyzedAt":"2026-09-04T07:54:14.808Z","contentChangedAt":"2026-09-04T07:54:14.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}