{"record":{"id":"71bd2d370067dbb6","repo":"docker/cli","slug":"error-saving-credentials-v","errorCode":null,"errorMessage":"error saving credentials: %v","messagePattern":"error saving credentials: (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cli/command/registry/login.go","lineNumber":334,"sourceCode":"\t\treturn \"\", err\n\t}\n\n\treturn response.Auth.Status, nil\n}\n\nfunc storeCredentials(cfg *configfile.ConfigFile, authConfig registrytypes.AuthConfig) error {\n\tcreds := cfg.GetCredentialsStore(authConfig.ServerAddress)\n\tif err := creds.Store(configtypes.AuthConfig{\n\t\tUsername:      authConfig.Username,\n\t\tPassword:      authConfig.Password,\n\t\tServerAddress: authConfig.ServerAddress,\n\n\t\t// TODO(thaJeztah): Are these expected to be included?\n\t\tAuth:          authConfig.Auth,\n\t\tIdentityToken: authConfig.IdentityToken,\n\t\tRegistryToken: authConfig.RegistryToken,\n\t}); err != nil {\n\t\treturn fmt.Errorf(\"error saving credentials: %v\", err)\n\t}\n\n\treturn nil\n}\n\nfunc loginWithRegistry(ctx context.Context, apiClient client.SystemAPIClient, options client.RegistryLoginOptions) (client.RegistryLoginResult, error) {\n\tres, err := apiClient.RegistryLogin(ctx, options)\n\tif err != nil {\n\t\tif client.IsErrConnectionFailed(err) {\n\t\t\t// daemon isn't responding; attempt to login client side.\n\t\t\treturn loginClientSide(ctx, options)\n\t\t}\n\t\treturn client.RegistryLoginResult{}, err\n\t}\n\n\treturn res, nil\n}\n","sourceCodeStart":316,"sourceCodeEnd":352,"githubUrl":"https://github.com/docker/cli/blob/4f84911bfe8811e9b028e4b1fee8e7510be79387/cli/command/registry/login.go#L316-L352","documentation":"Returned by storeCredentials (registry/login.go:334) wrapping the error from the credentials store's Store method. After a successful registry login the CLI persists the auth config via the configured credentials helper (file, osxkeychain, wincred, pass, etc.); any failure there is wrapped here. Note it uses %v, so the chain is not unwrappable via errors.Is.","triggerScenarios":"Login succeeds against the registry but writing to ~/.docker/config.json or the native credential helper fails. Common with `credsStore` set to a helper binary that is missing, broken, or locked (e.g. docker-credential-osxkeychain on a locked keychain).","commonSituations":"Missing docker-credential-* binary on PATH, keychain locked on macOS, file permission/ownership issues on ~/.docker/config.json, full disk, or a misspelled credsStore/credHelpers entry in config.json.","solutions":["Install/verify the configured credential helper binary (e.g. docker-credential-osxkeychain) is on PATH.","Check permissions and ownership of ~/.docker/config.json and ~/.docker/.","Fix or remove a broken `credsStore`/`credHelpers` entry in config.json if you do not need a native helper.","Unlock the keychain (macOS) or unlock the pass store (Linux) and retry."],"exampleFix":"// before: config.json has \"credsStore\": \"osxkeychain\" but binary missing\n// after: install helper and retry\nbrew install docker-credential-helper   # or ship the binary on PATH\ndocker login","handlingStrategy":"try-catch","validationCode":"// Pre-flight: ensure the configured credential helper binary is present.\nfunc ensureCredHelper(cfg *configfile.ConfigFile) error {\n    helper := cfg.CredentialsStore\n    if helper != \"\" {\n        if _, err := exec.LookPath(\"docker-credential-\" + helper); err != nil {\n            return fmt.Errorf(\"credential helper %q not found on PATH\", helper)\n        }\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"// Distinguish store failures from auth failures; do not leak credentials.\nif err := storeCredentials(cfg, auth); err != nil {\n    if strings.Contains(err.Error(), \"error saving credentials\") {\n        log.Printf(\"login ok but credential store failed: %v\", err)\n        // advise user to fix credsStore/credHelpers, do not retry blindly\n    }\n    return err\n}","preventionTips":["Install the docker-credential-* helper matching your credsStore setting.","Keep ~/.docker/config.json writable and correctly owned.","Avoid %v-only wrapping if you need errors.Is matching (this error uses %v)."],"tags":["registry","login","credentials","config","docker-cli"],"backgroundTag":null,"analyzedSha":"4f84911bfe8811e9b028e4b1fee8e7510be79387","analyzedAt":"2026-08-07T12:15:29.814Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}