{"record":{"id":"ea70dba3033a0f60","repo":"docker/cli","slug":"failed-to-store-tokens-w","errorCode":null,"errorMessage":"failed to store tokens: %w","messagePattern":"failed to store tokens: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/oauth/manager/manager.go","lineNumber":144,"sourceCode":"\n\t_, _ = fmt.Fprint(w, \"\\nWaiting for authentication in the browser…\\n\")\n\tvar tokenRes api.TokenResponse\n\tselect {\n\tcase <-ctx.Done():\n\t\treturn nil, errors.New(\"login canceled\")\n\tcase err := <-waitForTokenErrChan:\n\t\treturn nil, fmt.Errorf(\"failed waiting for authentication: %w\", err)\n\tcase tokenRes = <-tokenResChan:\n\t}\n\n\tclaims, err := oauth.GetClaims(tokenRes.AccessToken)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse token claims: %w\", err)\n\t}\n\n\terr = m.storeTokensInStore(tokenRes, claims.Domain.Username)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to store tokens: %w\", err)\n\t}\n\n\tpat, err := m.api.GetAutoPAT(ctx, m.audience, tokenRes)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &types.AuthConfig{\n\t\tUsername:      claims.Domain.Username,\n\t\tPassword:      pat,\n\t\tServerAddress: registry.IndexServer,\n\t}, nil\n}\n\n// Logout fetches the refresh token from the store and revokes it\n// with the configured oauth tenant. The stored access and refresh\n// tokens are then erased from the store.\n// If the refresh token is not found in the store, an error is not","sourceCodeStart":126,"sourceCodeEnd":162,"githubUrl":"https://github.com/docker/cli/blob/4f84911bfe8811e9b028e4b1fee8e7510be79387/internal/oauth/manager/manager.go#L126-L162","documentation":"Returned by OAuthManager.Login when storeTokensInStore fails. After parsing claims, the manager persists both the access token (under accessTokenKey) and refresh token (refreshTokenKey, as '<refresh>..<access>' split) into the credential store; if either Store call errors, login fails wrapped with %w.","triggerScenarios":"The credential store backend (e.g. pass/darwin keychain/wincred/secretservice/file) rejects the write — locked keyring, missing helper binary, permission denied on ~/.docker/config.json, disk full.","commonSituations":"GNOME keyring locked; `pass` not initialized (no gpg key); credential helper binary missing; read-only home; corrupt config.json; CI with no usable secret store.","solutions":["Ensure the credential helper is installed and unlocked (e.g. `pass init <gpg-key>`, unlock keychain).","Set credsStore/credHelpers correctly in ~/.docker/config.json, or remove them to use the file store.","Check write permissions and free space on ~/.docker/config.json.","Re-run `docker login` after fixing the store."],"exampleFix":"# before: pass not initialized -> failed to store tokens\npass init A1B2C3D4\n# config.json uses credsStore=pass; ensure helper exists\n{\n  \"credsStore\": \"pass\"\n}\ndocker login\n# fallback: use file store (remove credsStore) for CI","handlingStrategy":"try-catch","validationCode":"// ensure the credential store is writable before login\nif err := store.Store(types.AuthConfig{Username:\"_probe\", Password:\"\", ServerAddress:\"_probe\"}); err != nil { return err }","typeGuard":null,"tryCatchPattern":"if isStoreError(err) { // locked keyring / missing helper\n    configureFileStore(); retry login\n}","preventionTips":["Install and initialize the credential helper before login.","Validate the store with a probe write in CI setup.","Keep ~/.docker/config.json writable."],"tags":["oauth","credential-store","auth","docker-hub","storage"],"backgroundTag":null,"analyzedSha":"4f84911bfe8811e9b028e4b1fee8e7510be79387","analyzedAt":"2026-08-07T12:15:29.814Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}