larksuite/cli · error
dpapi protect failed: %w
Error message
dpapi protect failed: %w
What it means
This error wraps a failure of Windows DPAPI (CryptProtectData) when the keychain encrypts a secret before storing it in the registry. platformSet derives per-service/account entropy, calls dpapiProtect to encrypt the plaintext, and if that OS call fails the error is wrapped and propagated — nothing is written to the registry. The %w keeps the underlying syscall/OLE error for errors.Is/As.
Source
Thrown at internal/keychain/keychain_windows.go:124
b.Data = nil
b.Size = 0
}
// platformGet retrieves a value from the Windows registry.
func platformGet(service, account string) (string, error) {
v, ok := registryGet(service, account)
if !ok {
return "", nil
}
return v, nil
}
// platformSet stores a value in the Windows registry.
func platformSet(service, account, data string) error {
entropy := dpapiEntropy(service, account)
protected, err := dpapiProtect([]byte(data), entropy)
if err != nil {
return fmt.Errorf("dpapi protect failed: %w", err)
}
return registrySet(service, account, protected)
}
// platformRemove deletes a value from the Windows registry.
func platformRemove(service, account string) error {
return registryRemove(service, account)
}
// registryGet retrieves a string value from the registry under the given service and account.
func registryGet(service, account string) (string, bool) {
keyPath := registryPathForService(service)
k, err := registry.OpenKey(registry.CURRENT_USER, keyPath, registry.QUERY_VALUE)
if err != nil {
return "", false
}
defer k.Close()
View on GitHub (pinned to 7fd6ef3c07)
Solutions
- Read the wrapped cause for the specific DPAPI/Win32 error code.
- Ensure the process runs in an interactive user session with a loaded user profile (not a bare service/Session 0 context).
- If the user profile or master keys are corrupted, restore DPAPI keys from backup or recreate the user profile.
- As a fallback, switch the credential storage backend (e.g. plaintext-with-permissions or OS-independent store) if the CLI supports it.
Example fix
// before: running under a service with no user profile C:\> sc create svc binPath= lark-cli.exe // DPAPI fails // after: run in the user's interactive session C:\Users\dev> lark-cli auth login
Defensive patterns
Strategy: validation
Validate before calling
// Windows: verify a user profile with DPAPI is available before storing secrets
if !isInteractiveSession() || !userProfileLoaded() {
return errors.New("DPAPI requires an interactive user session with a loaded profile")
} Try / catch
if err := keychain.Set(service, account, secret); err != nil {
if strings.HasPrefix(err.Error(), "dpapi protect failed:") {
return fmt.Errorf("cannot encrypt credential (profile/DPAPI issue), run in an interactive session: %w", err)
}
return err
} Prevention
- Never store secrets from Session 0 / service contexts that lack a user profile.
- Back up DPAPI master keys for domain users before password resets.
- Test credential storage after major Windows/profile changes.
- Prefer a documented fallback backend when DPAPI is unavailable.
When it happens
Trigger: platformSet on Windows calls dpapiProtect([]byte(data), entropy) and the CryptProtectData call returns an error — before any registry write occurs.
Common situations: Corrupted user profile or DPAPI master keys; running as a service account/CI without a loaded user profile; credential roaming issues after domain password reset without key backup; running in a container or restricted token lacking DPAPI access.
Related errors
- registry create/open failed: %w
- registry set failed: %w
- keychain: item not found
- keychain not initialized
- keychain access blocked
AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04).
Data as JSON: /api/errors/ffa557f0d964805f.
Report an issue: GitHub.