{"record":{"id":"645b6030ba0e14f0","repo":"badges/shields","slug":"tag-not-found-645b60","errorCode":null,"errorMessage":"tag not found","messagePattern":"tag not found","errorType":"exception","errorClass":"NotFound","httpStatus":404,"severity":"error","filePath":"services/npm/npm-base.js","lineNumber":139,"sourceCode":"      url = `${registryUrl}/${scoped}`\n    }\n    const json = await this._requestJson({\n      // We don't validate here because we need to pluck the desired subkey first.\n      schema: Joi.any(),\n      url,\n      httpErrors: { 404: 'package not found' },\n    })\n\n    let packageData\n    if (scope === undefined && tag === undefined) {\n      packageData = json\n    } else {\n      const registryTag = tag || 'latest'\n      let latestVersion\n      try {\n        latestVersion = json['dist-tags'][registryTag]\n      } catch (e) {\n        throw new NotFound({ prettyMessage: 'tag not found' })\n      }\n      try {\n        packageData = json.versions[latestVersion]\n      } catch (e) {\n        throw new InvalidResponse({ prettyMessage: 'invalid json response' })\n      }\n    }\n\n    return this.constructor._validate(packageData, packageDataSchema)\n  }\n\n  async fetch({\n    registryUrl,\n    scope,\n    packageName,\n    schema,\n    abbreviated = false,\n  }) {","sourceCodeStart":121,"sourceCodeEnd":157,"githubUrl":"https://github.com/badges/shields/blob/766fd8bc89a90b8534dc573ab72dec30215ab1ec/services/npm/npm-base.js#L121-L157","documentation":"In npm-base's fetchPackageData, when no explicit version is requested the service resolves the package via a dist-tag (default 'latest'). It reads json['dist-tags'][registryTag] and, when that lookup fails to yield a usable version, throws NotFound 'tag not found'. Note the try/catch here actually only catches exceptions; in practice a missing tag yields undefined and the error effectively fires when the tag is absent or the JSON shape is unexpected.","triggerScenarios":"Requesting a badge with ?tag=beta (or any tag) that the package's dist-tags object does not contain; a registry response missing the 'dist-tags' key entirely; typo'd tag names in the badge URL.","commonSituations":"Packages that never published a 'next'/'beta' tag being queried with those tags; tags deleted after a publish was undone; third-party registries returning non-standard metadata without dist-tags.","solutions":["List the package's actual tags (npm dist-tags ls <pkg> or the registry dist-tags endpoint) and use one that exists","Omit the tag parameter to use the default 'latest' tag","Create the missing tag with `npm dist-tag add <pkg>@<version> <tag>` if you own the package","If you maintain the badge service, replace the try/catch with an explicit `if (!latestVersion) throw new NotFound(...)` check"],"exampleFix":"// before\n<service>/<pkg>/badge.svg?tag=canary   // no 'canary' dist-tag\n// after\n<service>/<pkg>/badge.svg?tag=next     // existing dist-tag, or omit ?tag","handlingStrategy":"type-guard","validationCode":"const meta = await fetch(`${registry}/${pkg}`).then(r => r.json())\nconst tags = meta && meta['dist-tags'] ? Object.keys(meta['dist-tags']) : []\nif (tag && !tags.includes(tag)) throw new Error(`tag '${tag}' not in [${tags.join(', ')}]`)","typeGuard":"function hasDistTag(meta, tag) {\n  return Boolean(meta && meta['dist-tags'] && typeof meta['dist-tags'][tag || 'latest'] === 'string')\n}","tryCatchPattern":"try {\n  return await npmBadge({ pkg, tag })\n} catch (e) {\n  if (e instanceof NotFound && e.message === 'tag not found') {\n    return npmBadge({ pkg }) // fall back to 'latest'\n  }\n  throw e\n}","preventionTips":["Run `npm dist-tags ls <pkg>` before hardcoding a tag in a badge URL","Default to omitting ?tag so 'latest' is used","Never rely on try/catch around plain property access — missing keys return undefined, not throw","Validate tag names against the registry's dist-tags response in your URL builder"],"tags":["npm","not-found","dist-tags","registry"],"backgroundTag":"dist-tag-not-found","analyzedSha":"766fd8bc89a90b8534dc573ab72dec30215ab1ec","analyzedAt":"2026-08-30T01:40:27.499Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}