badges/shields · error · NotFound

tag not found

Error message

tag not found

What it means

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.

Source

Thrown at services/npm/npm-base.js:139

      url = `${registryUrl}/${scoped}`
    }
    const json = await this._requestJson({
      // We don't validate here because we need to pluck the desired subkey first.
      schema: Joi.any(),
      url,
      httpErrors: { 404: 'package not found' },
    })

    let packageData
    if (scope === undefined && tag === undefined) {
      packageData = json
    } else {
      const registryTag = tag || 'latest'
      let latestVersion
      try {
        latestVersion = json['dist-tags'][registryTag]
      } catch (e) {
        throw new NotFound({ prettyMessage: 'tag not found' })
      }
      try {
        packageData = json.versions[latestVersion]
      } catch (e) {
        throw new InvalidResponse({ prettyMessage: 'invalid json response' })
      }
    }

    return this.constructor._validate(packageData, packageDataSchema)
  }

  async fetch({
    registryUrl,
    scope,
    packageName,
    schema,
    abbreviated = false,
  }) {

View on GitHub (pinned to 766fd8bc89)

Solutions

  1. List the package's actual tags (npm dist-tags ls <pkg> or the registry dist-tags endpoint) and use one that exists
  2. Omit the tag parameter to use the default 'latest' tag
  3. Create the missing tag with `npm dist-tag add <pkg>@<version> <tag>` if you own the package
  4. If you maintain the badge service, replace the try/catch with an explicit `if (!latestVersion) throw new NotFound(...)` check

Example fix

// before
<service>/<pkg>/badge.svg?tag=canary   // no 'canary' dist-tag
// after
<service>/<pkg>/badge.svg?tag=next     // existing dist-tag, or omit ?tag
Defensive patterns

Strategy: type-guard

Validate before calling

const meta = await fetch(`${registry}/${pkg}`).then(r => r.json())
const tags = meta && meta['dist-tags'] ? Object.keys(meta['dist-tags']) : []
if (tag && !tags.includes(tag)) throw new Error(`tag '${tag}' not in [${tags.join(', ')}]`)

Type guard

function hasDistTag(meta, tag) {
  return Boolean(meta && meta['dist-tags'] && typeof meta['dist-tags'][tag || 'latest'] === 'string')
}

Try / catch

try {
  return await npmBadge({ pkg, tag })
} catch (e) {
  if (e instanceof NotFound && e.message === 'tag not found') {
    return npmBadge({ pkg }) // fall back to 'latest'
  }
  throw e
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of badges/shields@766fd8bc89 (2026-08-30). Data as JSON: /api/errors/645b6030ba0e14f0. Report an issue: GitHub.