{"record":{"id":"86fde53b7e8d2b1e","repo":"Budibase/budibase","slug":"npm-tarball-url-not-found","errorCode":null,"errorMessage":"NPM tarball url not found","messagePattern":"NPM tarball url not found","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/server/src/api/controllers/plugin/npm.ts","lineNumber":57,"sourceCode":"      parsedInput.hostname !== \"www.npmjs.com\" ||\n      !parsedInput.pathname.startsWith(\"/package/\")\n    ) {\n      throw new Error(\"The plugin origin must be from NPM\")\n    }\n    const packageName = parsedInput.pathname.replace(\"/package/\", \"\").trim()\n    const npmPackageURl = `https://registry.npmjs.org/${packageName}`\n    const response = await coreUtils.fetchWithBlacklist(npmPackageURl)\n    if (response.status !== 200) {\n      throw new Error(\"NPM Package not found\")\n    }\n\n    let npmDetails = await response.json()\n    pluginName = npmDetails.name\n    const npmVersion = npmDetails[\"dist-tags\"].latest\n    npmTarballUrl = npmDetails?.versions?.[npmVersion]?.dist?.tarball\n\n    if (!npmTarballUrl) {\n      throw new Error(\"NPM tarball url not found\")\n    }\n  }\n\n  const path = await downloadUnzipTarball(npmTarballUrl, pluginName, headers)\n  const pluginRoot = join(path, \"package\", \"dist\")\n  try {\n    return await getPluginMetadata(pluginRoot, path)\n  } catch (err) {\n    deleteFolderFileSystem(path)\n    throw err\n  }\n}\n","sourceCodeStart":39,"sourceCodeEnd":70,"githubUrl":"https://github.com/Budibase/budibase/blob/a81a902e9a8fe55b467d106765f6638f12e35c49/packages/server/src/api/controllers/plugin/npm.ts#L39-L70","documentation":"Thrown when NPM registry metadata was fetched but no tarball URL could be derived from dist-tags.latest -> versions[latest].dist.tarball, so there is nothing to download.","triggerScenarios":"The registry response lacks a 'dist-tags' latest entry, the latest version object has no dist.tarball, or the response shape is unexpected (e.g. a deprecation/mirror response).","commonSituations":"Malformed or proxied registry responses; packages with no published versions; NPM registry API changes; a mirror returning partial metadata.","solutions":["Confirm the package has at least one published version and a valid 'latest' dist-tag","Check registry response: curl https://registry.npmjs.org/<pkg> | jq '.\"dist-tags\", .versions[.\"dist-tags\".latest].dist.tarball'","Ensure no proxy/mirror is stripping fields from the registry response","Retry if the registry returned a transient partial response"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"const meta = await (await fetch(`https://registry.npmjs.org/${packageName}`)).json()\nconst latest = meta['dist-tags']?.latest\nif (!meta?.versions?.[latest]?.dist?.tarball) throw new Error('Registry metadata has no tarball for latest version')","typeGuard":"function hasTarball(meta: unknown): meta is { name: string; 'dist-tags': { latest: string }; versions: Record<string, { dist: { tarball: string } }> } {\n  const m = meta as any\n  return !!m?.['dist-tags']?.latest && !!m?.versions?.[m['dist-tags'].latest]?.dist?.tarball\n}","tryCatchPattern":"try {\n  await npmUpload({ input })\n} catch (err) {\n  if (err.message === 'NPM tarball url not found') {\n    // inspect registry metadata / retry — likely a mirror or API response issue\n  }\n}","preventionTips":["Verify the package has published versions and a 'latest' dist-tag","Bypass mirrors/proxies that may strip dist fields","Spot-check registry JSON before programmatic uploads"],"tags":["npm","network","plugins","registry"],"backgroundTag":"npm-package-not-found","analyzedSha":"a81a902e9a8fe55b467d106765f6638f12e35c49","analyzedAt":"2026-08-29T01:03:10.972Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}