{"record":{"id":"6564ff2f3005dc9a","repo":"nodejs/node","slug":"token-id-id-was-ambiguous-a-new-token-may-ha","errorCode":null,"errorMessage":"Token ID \"${id}\" was ambiguous, a new token may have been created since you last ran `npm token list`.","messagePattern":"Token ID \"(.+?)\" was ambiguous, a new token may have been created since you last ran `npm token list`\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"deps/npm/lib/commands/token.js","lineNumber":126,"sourceCode":"    }\n  }\n\n  async rm (args) {\n    if (args.length === 0) {\n      throw this.usageError('`<tokenKey>` argument is required.')\n    }\n\n    const json = this.npm.config.get('json')\n    const parseable = this.npm.config.get('parseable')\n    const toRemove = []\n    log.info('token', `removing ${toRemove.length} tokens`)\n    const tokens = await paginate('/-/npm/v1/tokens', this.npm.flatOptions)\n    for (const id of args) {\n      const matches = tokens.filter(token => token.key.indexOf(id) === 0)\n      if (matches.length === 1) {\n        toRemove.push(matches[0].key)\n      } else if (matches.length > 1) {\n        throw new Error(\n          `Token ID \"${id}\" was ambiguous, a new token may have been created since you last ran \\`npm token list\\`.`\n        )\n      } else {\n        const tokenMatches = tokens.some(t => id.indexOf(t.token) === 0)\n        if (!tokenMatches) {\n          throw new Error(`Unknown token id or value \"${id}\".`)\n        }\n\n        toRemove.push(id)\n      }\n    }\n    for (const tokenKey of toRemove) {\n      await otplease(this.npm, this.npm.flatOptions, opts =>\n        fetch(`/-/npm/v1/tokens/token/${tokenKey}`, {\n          ...opts,\n          method: 'DELETE',\n          ignoreBody: true,\n        })","sourceCodeStart":108,"sourceCodeEnd":144,"githubUrl":"https://github.com/nodejs/node/blob/1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e/deps/npm/lib/commands/token.js#L108-L144","documentation":"Thrown by `npm token rm` when the given id is a prefix that matches more than one token's `key`. npm refuses to guess which token to delete, and hints that a newer token may have shifted the matching set since the last `npm token list`.","triggerScenarios":"In the revoke loop, `tokens.filter(t => t.key.indexOf(id) === 0).length > 1` — the id is a prefix of two or more token keys.","commonSituations":"Using a short id prefix that several tokens share; revoking after new tokens were created (CI rotations) that share the same prefix; copying only the first few characters of a token id.","solutions":["Run `npm token list` to get current full token ids, then pass a longer/unique prefix or the full id.","Pass the complete token key to disambiguate.","If prefix collisions are common, revoke tokens individually with the full id."],"exampleFix":"// before\nnpm token rm abc123   // matches 2 tokens\n// after\nnpm token rm abc123def456-full-key","handlingStrategy":"validation","validationCode":"function resolveTokenId(id, tokens) {\n  const matches = tokens.filter(t => t.key.indexOf(id) === 0)\n  if (matches.length > 1) {\n    throw new Error(`Token id \"${id}\" is ambiguous (${matches.length} matches). Use the full key.`)\n  }\n  return matches[0]?.key ?? null\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always pass the full token id/key, not a prefix.","Re-run `npm token list` immediately before revoking to get a current view.","In rotation scripts, target one token at a time with its full key."],"tags":["token","revoke","ambiguous","npm-cli","auth"],"backgroundTag":null,"analyzedSha":"1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e","analyzedAt":"2026-08-13T00:53:24.642Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}