{"record":{"id":"c91dd7aa72c6fb17","repo":"badges/shields","slug":"unable-to-select-next-libraries-io-token-from-pool","errorCode":null,"errorMessage":"Unable to select next Libraries.io token from pool","messagePattern":"Unable to select next Libraries\\.io token from pool","errorType":"exception","errorClass":"ImproperlyConfigured","httpStatus":null,"severity":"error","filePath":"services/librariesio/librariesio-api-provider.js","lineNumber":79,"sourceCode":"  updateToken({ token, res }) {\n    const { totalUsesRemaining, nextReset } = this.getRateLimitFromHeaders({\n      headers: res.headers,\n      token,\n    })\n    token.update(totalUsesRemaining, nextReset)\n  }\n\n  async fetch(requestFetcher, url, options = {}) {\n    const { baseUrl } = this\n\n    let token\n    let tokenString\n    if (this.withPooling) {\n      try {\n        token = this.standardTokens.next()\n      } catch (e) {\n        log.error(e)\n        throw new ImproperlyConfigured({\n          prettyMessage: 'Unable to select next Libraries.io token from pool',\n        })\n      }\n      tokenString = token.id\n    } else {\n      tokenString = this.globalToken\n    }\n\n    const mergedOptions = {\n      ...options,\n      ...{\n        headers: {\n          'User-Agent': userAgent,\n          ...options.headers,\n        },\n        searchParams: {\n          api_key: tokenString,\n          ...options.searchParams,","sourceCodeStart":61,"sourceCodeEnd":97,"githubUrl":"https://github.com/badges/shields/blob/766fd8bc89a90b8534dc573ab72dec30215ab1ec/services/librariesio/librariesio-api-provider.js#L61-L97","documentation":"Libraries.io requests in Shields use a pool of API tokens that are rotated to spread rate limits. When withPooling is enabled, the service pulls the next token from StandardTokens.next(); if that call throws (e.g. no tokens are available or the pool is misconfigured), the error is wrapped in an ImproperlyConfigured with this message. It is a service configuration problem, not a network or user error.","triggerScenarios":"Instantiating the Libraries.io provider with withPooling=true but an empty or invalid token pool, so standardTokens.next() throws when fetch() selects a token.","commonSituations":"Deploying without configuring the Libraries.io token pool in the environment, all configured tokens having been removed or invalidated, or accidentally enabling pooling when only a single global token is set.","solutions":["Add at least one valid Libraries.io API token to the configured token pool (env/config).","If you only have one token, disable pooling and set globalToken instead.","Verify the token pool module (StandardTokens) is constructed with the configured credentials and that token entries have an id field.","Regenerate the Libraries.io API key if existing tokens were revoked."],"exampleFix":"// before\nwithPooling: true  // but no tokens in pool\n// after\nwithPooling: false,\nglobalToken: process.env.LIBRARIES_IO_TOKEN","handlingStrategy":"try-catch","validationCode":"if (!tokens || tokens.length === 0) throw new Error('Libraries.io token pool is empty; configure LIBRARIES_IO_TOKEN')","typeGuard":"null","tryCatchPattern":"try {\n  const badge = await librariesioProvider.fetch(params)\n} catch (e) {\n  if (e instanceof ImproperlyConfigured && e.prettyMessage.includes('token')) {\n    // fix config: supply/rotate Libraries.io tokens, then retry\n  }\n  throw e\n}","preventionTips":["Always provision at least one valid Libraries.io token in the environment before enabling the service.","Monitor Libraries.io rate limits and rotate tokens before expiry/revocation.","Only enable withPooling when the pool is guaranteed non-empty; otherwise use globalToken."],"tags":["configuration","token-pool","librariesio"],"backgroundTag":"missing-api-token","analyzedSha":"766fd8bc89a90b8534dc573ab72dec30215ab1ec","analyzedAt":"2026-08-30T01:40:27.499Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}