{"record":{"id":"1e7a8187bbcd6bd0","repo":"kopia/kopia","slug":"error-saving-password-in-os-keyring","errorCode":null,"errorMessage":"error saving password in OS keyring","messagePattern":"error saving password in OS keyring","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/passwordpersist/passwordpersist_keyring.go","lineNumber":54,"sourceCode":"\t\treturn \"\", errors.Wrap(err, \"error retrieving password from OS keyring, the keyring may be locked, attempt unlocking it using the OS-specific method\")\n\t}\n}\n\nfunc (keyringStrategy) PersistPassword(ctx context.Context, configFile, password string) error {\n\tlog(ctx).Debug(\"saving password to OS keyring...\")\n\n\terr := keyring.Set(getKeyringItemID(configFile), keyringUsername(ctx), password)\n\n\tswitch {\n\tcase err == nil:\n\t\tlog(ctx).Debug(\"Saved password in OS keyring\")\n\t\treturn nil\n\n\tcase errors.Is(err, keyring.ErrUnsupportedPlatform):\n\t\treturn ErrUnsupported\n\n\tdefault:\n\t\treturn errors.Wrap(err, \"error saving password in OS keyring\")\n\t}\n}\n\nfunc (keyringStrategy) DeletePassword(ctx context.Context, configFile string) error {\n\terr := keyring.Delete(getKeyringItemID(configFile), keyringUsername(ctx))\n\n\tswitch {\n\tcase err == nil:\n\t\tlog(ctx).Infof(\"deleted repository password for %v.\", configFile)\n\t\treturn nil\n\n\tcase errors.Is(err, keyring.ErrUnsupportedPlatform):\n\t\treturn ErrUnsupported\n\n\tcase errors.Is(err, keyring.ErrNotFound):\n\t\treturn ErrPasswordNotFound\n\n\tdefault:","sourceCodeStart":36,"sourceCodeEnd":72,"githubUrl":"https://github.com/kopia/kopia/blob/82495e54b584c1ef6073c9e1be048f57f8aef078/internal/passwordpersist/passwordpersist_keyring.go#L36-L72","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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)."],"exampleFix":"// before\nif err := passwordpersist.PersistPassword(ctx, cfg, pass); err != nil {\n    return err\n}\n// after\nif err := passwordpersist.PersistPassword(ctx, cfg, pass); err != nil {\n    if errors.Is(err, passwordpersist.ErrUnsupported) {\n        log(ctx).Warn(\"no OS keyring; keeping password in config\")\n    } else {\n        return err\n    }\n}","handlingStrategy":"try-catch","validationCode":"// Go: detect keyring availability before persisting\nfunc keyringUsable() error {\n    return keyring.Set(\"kopia-probe\", \"kopia-probe\", \"probe\") // check err\n}","typeGuard":"func isKeyringUnsupported(err error) bool {\n    return errors.Is(err, passwordpersist.ErrUnsupported)\n}","tryCatchPattern":"if err := passwordpersist.PersistPassword(ctx, cfg, pass); err != nil {\n    switch {\n    case errors.Is(err, passwordpersist.ErrUnsupported):\n        log.Warn(\"no OS keyring available\")\n    default:\n        return fmt.Errorf(\"keyring persist failed: %w\", err)\n    }\n}","preventionTips":["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"],"tags":["keyring","password-storage","os-integration"],"backgroundTag":"unsupported-platform","analyzedSha":"82495e54b584c1ef6073c9e1be048f57f8aef078","analyzedAt":"2026-09-07T20:35:21.689Z","contentChangedAt":"2026-09-07T20:35:21.689Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}