withastro/astro · error · Error

Unable to resolve "${packageInfo.name}"

Error message

Unable to resolve "${packageInfo.name}"

What it means

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.

Source

Thrown at packages/upgrade/src/actions/verify.ts:147

		return false;
	}
	for (const packageInfo of ctx.packages) {
		if (!packageInfo.targetVersion) {
			return false;
		}
	}
	return true;
}

export async function resolveTargetVersion(
	packageInfo: PackageInfo,
	registry: string,
): Promise<void> {
	const packageMetadata = await fetch(`${registry}/${packageInfo.name}`, {
		headers: { accept: 'application/vnd.npm.install-v1+json' },
	});
	if (packageMetadata.status >= 400) {
		throw new Error(`Unable to resolve "${packageInfo.name}"`);
	}
	const { 'dist-tags': distTags } = await packageMetadata.json();
	let version = distTags[packageInfo.targetVersion];
	if (version) {
		const currentCoerced = semverCoerce(packageInfo.currentVersion);
		const targetParsed = semverParse(version);
		// If the dist-tag points to a version older than the installed one, fall back to latest.
		if (currentCoerced && targetParsed && semverGt(currentCoerced, targetParsed)) {
			packageInfo.targetVersion = 'latest';
			version = distTags.latest;
		} else {
			packageInfo.tag = packageInfo.targetVersion;
			packageInfo.targetVersion = version;
		}
	} else {
		packageInfo.targetVersion = 'latest';
		version = distTags.latest;
	}

View on GitHub (pinned to d081033d5f)

Solutions

  1. 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.
  2. 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.
  3. Check connectivity/proxy: run `curl -I ${registry}/${name}` from the same environment and confirm it is not a 401/403/404/5xx.
  4. Confirm the package name spelling and scope (e.g. `@astrojs/check`, not `astrojs/check`).

Example fix

// before
const packageMetadata = await fetch(`${registry}/${packageInfo.name}`, {
  headers: { accept: 'application/vnd.npm.install-v1+json' },
});
if (packageMetadata.status >= 400) {
  throw new Error(`Unable to resolve "${packageInfo.name}"`);
}

// after — surface the HTTP status so the failure is debuggable
if (packageMetadata.status >= 400) {
  throw new Error(
    `Unable to resolve "${packageInfo.name}" (registry ${registry} returned ${packageMetadata.status})`,
  );
}
Defensive patterns

Strategy: retry

Validate before calling

// Validate the package is resolvable before calling resolveTargetVersion
import { fetch } from 'undici';
async function packageResolves(registry: string, name: string): Promise<boolean> {
  const res = await fetch(`${registry}/${encodeURIComponent(name)}`);
  return res.status < 400;
}
// call before resolveTargetVersion:
if (!(await packageResolves(registry, packageInfo.name))) {
  // surface a user-facing message instead of letting the tool throw
}

Type guard

function isValidPackageName(name: string): boolean {
  // npm scope/name rules
  return /^(?:@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/.test(name);
}

Try / catch

try {
  await resolveTargetVersion(packageInfo, registry);
} catch (e) {
  if (e instanceof Error && e.message.startsWith('Unable to resolve')) {
    // retry once, then report a registry/connectivity problem to the user
  } else throw e;
}

Prevention

When it happens

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

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

Related errors


AI-assisted analysis of withastro/astro@d081033d5f (2026-08-12). Data as JSON: /api/errors/438bda488a885dc4. Report an issue: GitHub.