{"record":{"id":"ac1e7bedb6954010","repo":"pnpm/pnpm","slug":"logout-failed","errorCode":"LOGOUT_FAILED","errorMessage":"Failed to log out of ${registry}. The registry rejected the token revocation request, and the token was not found in ${configPath}. The token may be configured in .npmrc or another config file and must be removed manually, and may still need to be revoked on the registry.","messagePattern":"Failed to log out of (.+?)\\. The registry rejected the token revocation request, and the token was not found in (.+?)\\. The token may be configured in \\.npmrc or another config file and must be removed manually, and may still need to be revoked on the registry\\.","errorType":"error_code","errorClass":"LogoutFailedError","httpStatus":null,"severity":"error","filePath":"pnpm11/auth/commands/src/logout.ts","lineNumber":133,"sourceCode":"  if (!token) {\n    throw new LogoutNotLoggedInError(registry)\n  }\n\n  const revokedOnRegistry = await tryRevokeToken({ context, opts, registry, token })\n\n  const configPath = path.join(opts.configDir, 'auth.ini')\n  const authIniSettings = await safeReadIniFile(readIniFile, configPath) as Record<string, unknown>\n\n  if (tokenKey in authIniSettings) {\n    await removeTokenFromAuthIni({ context, configPath, authIniSettings, tokenKey })\n  } else if (revokedOnRegistry) {\n    globalWarn(\n      `The auth token for ${registry} was not found in ${configPath}. ` +\n      'It may be configured in .npmrc or another config file. ' +\n      'The token was revoked on the registry but must be removed manually from that config file.'\n    )\n  } else {\n    throw new LogoutFailedError(registry, configPath)\n  }\n\n  return `Logged out of ${registry}`\n}\n\ninterface TryRevokeTokenParams {\n  context: Pick<LogoutContext, 'fetch' | 'globalInfo'>\n  opts: Pick<LogoutCommandOptions, 'fetchRetries' | 'fetchRetryFactor' | 'fetchRetryMaxtimeout' | 'fetchRetryMintimeout' | 'fetchTimeout'>\n  registry: string\n  token: string\n}\n\nasync function tryRevokeToken ({\n  context: { fetch, globalInfo },\n  opts,\n  registry,\n  token,\n}: TryRevokeTokenParams): Promise<boolean> {","sourceCodeStart":115,"sourceCodeEnd":151,"githubUrl":"https://github.com/pnpm/pnpm/blob/5b11d3a15b9022a2109cb18ed96a5d652630371f/pnpm11/auth/commands/src/logout.ts#L115-L151","documentation":"logout attempts two things: revoking the token on the registry and deleting it from pnpm's auth.ini. When the registry rejected the revocation AND the token key was not present in auth.ini, nothing could be done automatically, so LOGOUT_FAILED reports both facts and directs manual cleanup — the token likely lives in `.npmrc` or another config file and may still be valid on the registry.","triggerScenarios":"`pnpm logout` where the token is configured in `~/.npmrc` (not pnpm's auth.ini) and the revocation request fails — network error, 4xx/5xx from the registry, or an unimplemented revoke endpoint.","commonSituations":"Tokens set manually via `npm config set` or shared `.npmrc` files; enterprise registries without a revocation endpoint; tokens already revoked out of band; mixed npm/pnpm config setups.","solutions":["Remove the token manually from wherever it lives: search `~/.npmrc`, project `.npmrc`, and pnpm config files for `:_authToken` lines under that registry and delete them","Revoke the token separately via the registry's API or dashboard if it supports it","If the revocation failure looked transient (5xx, timeout), fix connectivity and rerun `pnpm logout` before doing manual cleanup","Verify with `pnpm whoami` afterwards that you are actually logged out"],"exampleFix":"# before\npnpm logout  # token in ~/.npmrc, revoke endpoint failed\n\n# after\n# 1) locate and delete the line:\n#   grep -n '_authToken' ~/.npmrc   ->  delete the matching :_authToken line\n# 2) revoke via registry dashboard if supported\npnpm whoami  # should now report not logged in","handlingStrategy":"validation","validationCode":"// before logout, locate where the token actually lives\nimport { existsSync, readFileSync } from 'node:fs'\nimport os from 'node:os'\nimport path from 'node:path'\n\nconst files = [path.join(os.homedir(), '.npmrc'), '.npmrc', path.join(configDir, 'auth.ini')]\nconst known = files.filter((f) => existsSync(f) && readFileSync(f, 'utf8').includes('_authToken'))\nif (known.length === 0) {\n  throw new Error('no token configured anywhere — logout will fail with NOT_LOGGED_IN')\n}\nif (!known.some((f) => f.endsWith('auth.ini'))) {\n  console.warn('token is outside auth.ini; if revocation fails, removal will be manual')\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Know where your token is stored before logging out: pnpm auth.ini vs ~/.npmrc vs project .npmrc","Verify the registry supports token revocation before expecting automated logout to succeed","In cleanup scripts, catch LOGOUT_FAILED and fall back to deleting the `_authToken` line from the config file"],"tags":["auth","logout","registry","configuration"],"backgroundTag":null,"analyzedSha":"5b11d3a15b9022a2109cb18ed96a5d652630371f","analyzedAt":"2026-08-16T13:18:59.198Z","schemaVersion":2},"datasetVersion":"2026-08-16T18:17:16.020Z"}