{"record":{"id":"133229eb5b8f8086","repo":"gastownhall/beads","slug":"credential-encryption-key-not-initialized","errorCode":null,"errorMessage":"credential encryption key not initialized","messagePattern":"credential encryption key not initialized","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/dolt/credentials.go","lineNumber":245,"sourceCode":"\t}\n\tnonce, ciphertext := encrypted[:nonceSize], encrypted[nonceSize:]\n\tplaintext, err := gcm.Open(nil, nonce, ciphertext, nil)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\treturn string(plaintext), nil\n}\n\n// encryptPassword encrypts a password using AES-GCM with the store's credential key.\nfunc (s *DoltStore) encryptPassword(password string) ([]byte, error) {\n\tif password == \"\" {\n\t\treturn nil, nil\n\t}\n\ts.mu.RLock()\n\tkey := s.credentialKey\n\ts.mu.RUnlock()\n\tif key == nil {\n\t\treturn nil, fmt.Errorf(\"credential encryption key not initialized\")\n\t}\n\treturn encryptWithKey(password, key)\n}\n\n// decryptPassword decrypts a password using AES-GCM with the store's credential key.\nfunc (s *DoltStore) decryptPassword(encrypted []byte) (string, error) {\n\tif len(encrypted) == 0 {\n\t\treturn \"\", nil\n\t}\n\ts.mu.RLock()\n\tkey := s.credentialKey\n\ts.mu.RUnlock()\n\tif key == nil {\n\t\treturn \"\", fmt.Errorf(\"credential encryption key not initialized\")\n\t}\n\treturn decryptWithKey(encrypted, key)\n}\n","sourceCodeStart":227,"sourceCodeEnd":263,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/dolt/credentials.go#L227-L263","documentation":"encryptPassword uses the store's in-memory credentialKey, which is loaded by ensureCredentialKey/initCredentialKey. This error is returned when encryptPassword is called before that initialization has happened, i.e. s.credentialKey is still nil. In normal usage addFederationPeer calls ensureCredentialKey first, so hitting this means encryption was invoked out of order or key initialization was skipped (e.g. empty beadsDir disables key loading entirely).","triggerScenarios":"s.encryptPassword is called while s.credentialKey == nil: an addFederationPeer path that skipped ensureCredentialKey, a store constructed without running initCredentialKey (beadsDir empty), or code/tests calling encryptPassword directly without initialization.","commonSituations":"Embedding the DoltStore in another tool and calling federation APIs without the store's normal open/initialization sequence; beadsDir empty (no filesystem path), which makes initCredentialKey a no-op so the key never loads; test fixtures constructing DoltStore directly.","solutions":["Call ensureCredentialKey(ctx) (the exported path: any AddFederationPeer call) before encrypting — do not invoke encryptPassword directly on a fresh store","Ensure the store's beadsDir is set to a valid .beads directory so initCredentialKey can load or create the key file","If integrating the store directly, replicate the open path that runs initCredentialKey before federation operations","In tests, initialize the key explicitly (temp beadsDir) before calling encryptPassword"],"exampleFix":"// before\nstore.encryptPassword(pwd) // panic-path: credential encryption key not initialized\n// after\nif err := store.ensureCredentialKey(ctx); err != nil { return err }\nenc, err := store.encryptPassword(pwd)","handlingStrategy":"validation","validationCode":"// Ensure key initialization ran before encryption\ndummy, err := store.encryptPassword(\"\")\n_ = dummy\nif err == nil {\n    // empty password short-circuits; instead verify via ensureCredentialKey:\n}\nif err := store.ensureCredentialKey(ctx); err != nil { return err }","typeGuard":null,"tryCatchPattern":"enc, err := store.encryptPassword(pwd)\nif err != nil && err.Error() == \"credential encryption key not initialized\" {\n    if err := store.ensureCredentialKey(ctx); err != nil { return err }\n    enc, err = store.encryptPassword(pwd)\n}\nreturn enc, err","preventionTips":["Always go through AddFederationPeer (which calls ensureCredentialKey) rather than internal encryptPassword","Never construct DoltStore directly in tools/tests without running the init/open sequence","Provide a valid beadsDir so key loading is not skipped","In tests, initialize the credential key in fixture setup"],"tags":["encryption","initialization","key-management","state"],"backgroundTag":"encryption-key-not-initialized","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}