kopia/kopia · error
error saving password in OS keyring
Error message
error saving password in OS keyring
What it means
PersistPassword failed to save the password into the OS keyring via the go-keyring library. The keyring backend returned an error that was neither ErrNotFound nor ErrUnsupportedPlatform, so kopia wraps it with this message. It indicates an OS-level keychain/keyring access problem, not an application-logic error.
Solutions
- Ensure an OS keyring service is available (gnome-keyring / KWallet on Linux, unlocked Keychain on macOS).
- Unlock the keychain or re-run and approve the keychain access prompt.
- Check the wrapped cause with errors.Is against keyring errors to distinguish denial from backend failure.
- Fall back to another persistence strategy (the multi-strategy wrapper already skips on ErrUnsupported).
Example fix
// before
if err := passwordpersist.PersistPassword(ctx, cfg, pass); err != nil {
return err
}
// after
if err := passwordpersist.PersistPassword(ctx, cfg, pass); err != nil {
if errors.Is(err, passwordpersist.ErrUnsupported) {
log(ctx).Warn("no OS keyring; keeping password in config")
} else {
return err
}
} Defensive patterns
Strategy: try-catch
Validate before calling
// Go: detect keyring availability before persisting
func keyringUsable() error {
return keyring.Set("kopia-probe", "kopia-probe", "probe") // check err
} Type guard
func isKeyringUnsupported(err error) bool {
return errors.Is(err, passwordpersist.ErrUnsupported)
} Try / catch
if err := passwordpersist.PersistPassword(ctx, cfg, pass); err != nil {
switch {
case errors.Is(err, passwordpersist.ErrUnsupported):
log.Warn("no OS keyring available")
default:
return fmt.Errorf("keyring persist failed: %w", err)
}
} Prevention
- Run a keyring probe (set/get/delete) at startup before relying on it
- On Linux, verify a Secret Service implementation is installed and D-Bus is running
- On macOS, pre-approve keychain access for the binary
- Handle ErrUnsupported explicitly with a fallback storage path
When it happens
Trigger: Calling passwordpersist.PersistPassword when keyring.Set fails: locked keychain, denied access prompt, no keyring daemon (Linux without gnome-keyring/KWallet/Secret Service), or a backend-specific I/O error.
Common situations: Headless Linux servers with no Secret Service or D-Bus; macOS Keychain access denied by user clicking 'Deny'; Windows Credential Manager corruption; SSH sessions without a running keyring daemon.
Understand the failure class
Background: "unsupported platform" / "not supported on this platform" errors: what they mean and how to fix them — this error's family across 47 libraries.
Related errors
- error persisting password
- unable to delete keyring item
- cannot get persistent password
- error getting persistent password
- error removing password from persistent storage
AI-assisted analysis of kopia/kopia@82495e54b5 (2026-09-07).
Data as JSON: /api/errors/1e7a8187bbcd6bd0.
Report an issue: GitHub.
Appendix: source
Thrown at internal/passwordpersist/passwordpersist_keyring.go:54
return "", errors.Wrap(err, "error retrieving password from OS keyring, the keyring may be locked, attempt unlocking it using the OS-specific method")
}
}
func (keyringStrategy) PersistPassword(ctx context.Context, configFile, password string) error {
log(ctx).Debug("saving password to OS keyring...")
err := keyring.Set(getKeyringItemID(configFile), keyringUsername(ctx), password)
switch {
case err == nil:
log(ctx).Debug("Saved password in OS keyring")
return nil
case errors.Is(err, keyring.ErrUnsupportedPlatform):
return ErrUnsupported
default:
return errors.Wrap(err, "error saving password in OS keyring")
}
}
func (keyringStrategy) DeletePassword(ctx context.Context, configFile string) error {
err := keyring.Delete(getKeyringItemID(configFile), keyringUsername(ctx))
switch {
case err == nil:
log(ctx).Infof("deleted repository password for %v.", configFile)
return nil
case errors.Is(err, keyring.ErrUnsupportedPlatform):
return ErrUnsupported
case errors.Is(err, keyring.ErrNotFound):
return ErrPasswordNotFound
default:View on GitHub (pinned to 82495e54b5)