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

  1. Ensure an OS keyring service is available (gnome-keyring / KWallet on Linux, unlocked Keychain on macOS).
  2. Unlock the keychain or re-run and approve the keychain access prompt.
  3. Check the wrapped cause with errors.Is against keyring errors to distinguish denial from backend failure.
  4. 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

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


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)