{"record":{"id":"438bda488a885dc4","repo":"withastro/astro","slug":"unable-to-resolve-packageinfo-name","errorCode":null,"errorMessage":"Unable to resolve \"${packageInfo.name}\"","messagePattern":"Unable to resolve \"(.+?)\"","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/upgrade/src/actions/verify.ts","lineNumber":147,"sourceCode":"\t\treturn false;\n\t}\n\tfor (const packageInfo of ctx.packages) {\n\t\tif (!packageInfo.targetVersion) {\n\t\t\treturn false;\n\t\t}\n\t}\n\treturn true;\n}\n\nexport async function resolveTargetVersion(\n\tpackageInfo: PackageInfo,\n\tregistry: string,\n): Promise<void> {\n\tconst packageMetadata = await fetch(`${registry}/${packageInfo.name}`, {\n\t\theaders: { accept: 'application/vnd.npm.install-v1+json' },\n\t});\n\tif (packageMetadata.status >= 400) {\n\t\tthrow new Error(`Unable to resolve \"${packageInfo.name}\"`);\n\t}\n\tconst { 'dist-tags': distTags } = await packageMetadata.json();\n\tlet version = distTags[packageInfo.targetVersion];\n\tif (version) {\n\t\tconst currentCoerced = semverCoerce(packageInfo.currentVersion);\n\t\tconst targetParsed = semverParse(version);\n\t\t// If the dist-tag points to a version older than the installed one, fall back to latest.\n\t\tif (currentCoerced && targetParsed && semverGt(currentCoerced, targetParsed)) {\n\t\t\tpackageInfo.targetVersion = 'latest';\n\t\t\tversion = distTags.latest;\n\t\t} else {\n\t\t\tpackageInfo.tag = packageInfo.targetVersion;\n\t\t\tpackageInfo.targetVersion = version;\n\t\t}\n\t} else {\n\t\tpackageInfo.targetVersion = 'latest';\n\t\tversion = distTags.latest;\n\t}","sourceCodeStart":129,"sourceCodeEnd":165,"githubUrl":"https://github.com/withastro/astro/blob/d081033d5fe8e8a68c4bbbad4af9d2deb9c74bca/packages/upgrade/src/actions/verify.ts#L129-L165","documentation":"Thrown by resolveTargetVersion in the upgrade tool when the npm registry responds with HTTP >= 400 to a packument (full package metadata) request for the package being upgraded. The upgrade CLI fetches `${registry}/${name}` to read dist-tags, so any 4xx/5xx (404 not found, registry outage, auth required) aborts the version resolution. It is a generic Error, not an AstroError, so it carries no code or hint.","triggerScenarios":"Calling the upgrade command against a package name that does not exist on the configured registry; using a custom/private registry that requires auth (returns 401/403); the registry host is down or returns 5xx; the packageInfo.name is mistyped or scoped incorrectly (e.g. missing @scope/).","commonSituations":"A developer runs `astro upgrade` or `astro upgrade --package <name>` while offline or behind a corporate proxy; using an internal Verdaccio/Nexus registry that needs a token; the package was renamed/deprecated on npm; a typo in a manually constructed PackageInfo.","solutions":["Verify the package exists on your registry: `npm view <name>` or open `${registry}/${name}` in a browser and confirm a 200 response with dist-tags.","If using a private/custom registry, ensure npm config (`.npmrc` NPM_CONFIG_REGISTRY, or the registry argument passed to the action) points to a registry that actually hosts the package and that auth is configured.","Check connectivity/proxy: run `curl -I ${registry}/${name}` from the same environment and confirm it is not a 401/403/404/5xx.","Confirm the package name spelling and scope (e.g. `@astrojs/check`, not `astrojs/check`)."],"exampleFix":"// before\nconst packageMetadata = await fetch(`${registry}/${packageInfo.name}`, {\n  headers: { accept: 'application/vnd.npm.install-v1+json' },\n});\nif (packageMetadata.status >= 400) {\n  throw new Error(`Unable to resolve \"${packageInfo.name}\"`);\n}\n\n// after — surface the HTTP status so the failure is debuggable\nif (packageMetadata.status >= 400) {\n  throw new Error(\n    `Unable to resolve \"${packageInfo.name}\" (registry ${registry} returned ${packageMetadata.status})`,\n  );\n}","handlingStrategy":"retry","validationCode":"// Validate the package is resolvable before calling resolveTargetVersion\nimport { fetch } from 'undici';\nasync function packageResolves(registry: string, name: string): Promise<boolean> {\n  const res = await fetch(`${registry}/${encodeURIComponent(name)}`);\n  return res.status < 400;\n}\n// call before resolveTargetVersion:\nif (!(await packageResolves(registry, packageInfo.name))) {\n  // surface a user-facing message instead of letting the tool throw\n}","typeGuard":"function isValidPackageName(name: string): boolean {\n  // npm scope/name rules\n  return /^(?:@[a-z0-9-~][a-z0-9-._~]*\\/)?[a-z0-9-~][a-z0-9-._~]*$/.test(name);\n}","tryCatchPattern":"try {\n  await resolveTargetVersion(packageInfo, registry);\n} catch (e) {\n  if (e instanceof Error && e.message.startsWith('Unable to resolve')) {\n    // retry once, then report a registry/connectivity problem to the user\n  } else throw e;\n}","preventionTips":["Pin the registry explicitly (NPM_CONFIG_REGISTRY or the action's registry arg) rather than relying on ambient config.","Validate package names before constructing PackageInfo.","Run `npm view <name>` as a preflight in CI before invoking the upgrade tool.","Ensure auth tokens for private registries are present in the environment."],"tags":["network","npm-registry","upgrade-tool","http-status"],"backgroundTag":null,"analyzedSha":"d081033d5fe8e8a68c4bbbad4af9d2deb9c74bca","analyzedAt":"2026-08-12T13:37:29.035Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}