{"record":{"id":"3f1bd529eecf6721","repo":"pnpm/pnpm","slug":"login-no-token","errorCode":"LOGIN_NO_TOKEN","errorMessage":"The registry did not return an authentication token","messagePattern":"The registry did not return an authentication token","errorType":"error_code","errorClass":"LoginNoTokenError","httpStatus":null,"severity":"error","filePath":"pnpm11/auth/commands/src/login.ts","lineNumber":363,"sourceCode":"      try {\n        const result = await addUser({\n          username,\n          password,\n          email,\n          otp,\n          registryUrl: registry,\n          fetch,\n        })\n        return result.token\n      } catch (err) {\n        if (err instanceof AddUserHttpError) {\n          if (err.status === 401 && err.responseHeaders.get('www-authenticate')?.includes('otp')) {\n            throw SyntheticOtpError.fromUnknownBody(globalWarn, err.responseJson)\n          }\n          throw new ClassicLoginError(err.status, err.responseText)\n        }\n        if (err instanceof AddUserNoTokenError) {\n          throw new LoginNoTokenError()\n        }\n        throw err\n      }\n    },\n  })\n\n  globalInfo(`Logged in as ${username}`)\n\n  return token\n}\n\nclass LoginNonInteractiveError extends PnpmError {\n  constructor () {\n    super('LOGIN_NON_INTERACTIVE', 'The login command requires an interactive terminal')\n  }\n}\n\nclass LoginInvalidResponseError extends PnpmError {","sourceCodeStart":345,"sourceCodeEnd":381,"githubUrl":"https://github.com/pnpm/pnpm/blob/5b11d3a15b9022a2109cb18ed96a5d652630371f/pnpm11/auth/commands/src/login.ts#L345-L381","documentation":"The registry answered the adduser request successfully but the response contained no usable token (AddUserNoTokenError), so pnpm has nothing to store and throws LOGIN_NO_TOKEN.","triggerScenarios":"`pnpm login` against a registry whose adduser endpoint returns 2xx with a body missing the `token` field (or an empty one).","commonSituations":"Misimplemented private registries or custom auth bridges; proxies stripping response fields; schema drift between the registry's adduser response and pnpm's parser.","solutions":["Create a token out-of-band (registry website → Access Tokens) and configure it: `pnpm config set //<registry-host>/:_authToken <token>`","Upgrade the registry software so its adduser response includes a token","Verify the endpoint shape: `curl -u user:pass <registry>/-/user/org.couchdb.user:user` should return an object containing `token`"],"exampleFix":"# before\npnpm login  # registry 2xx but no token in body\n\n# after\npnpm config set //registry.example.com/:_authToken eyJhbGciOi...\npnpm whoami  # verify","handlingStrategy":"fallback","validationCode":"const res = await fetch(`${registry}/-/user/org.couchdb.user:${encodeURIComponent(user)}`, {\n  headers: { authorization: `Basic ${Buffer.from(`${user}:${pass}`).toString('base64')}` },\n})\nconst body = await res.json().catch(() => null)\nif (res.ok && typeof body?.token !== 'string' || body?.token === '') {\n  console.error('registry does not return tokens from adduser; using manual _authToken')\n  await exec(`pnpm config set ${registryKey}:_authToken ${process.env.NPM_TOKEN}`)\n}","typeGuard":null,"tryCatchPattern":"try {\n  token = await runClassicLogin()\n} catch (err) {\n  if (err instanceof Error && err.message.includes('LOGIN_NO_TOKEN')) {\n    // fallback: out-of-band token created on the registry website\n    await exec(`pnpm config set ${registryKey}:_authToken ${process.env.NPM_TOKEN}`)\n    token = process.env.NPM_TOKEN\n  } else {\n    throw err\n  }\n}","preventionTips":["Contract-check that the registry's adduser response includes a token before relying on interactive login","Keep a website-issued access token as the automation path for registries with broken adduser","Upgrade self-hosted registries so login responses carry a token field"],"tags":["auth","login","registry","token"],"backgroundTag":null,"analyzedSha":"5b11d3a15b9022a2109cb18ed96a5d652630371f","analyzedAt":"2026-08-16T13:18:59.198Z","schemaVersion":2},"datasetVersion":"2026-08-16T18:17:16.020Z"}