angular/angular-cli · error · Error

Unsupported package specifier type: ${type}

Error message

Unsupported package specifier type: ${type}

What it means

The default branch of the type switch in PackageManager.getManifest. npm-package-arg resolved the specifier to a type the Angular CLI does not handle (anything other than range, version, tag, directory, file, remote, or git). This guards against unknown or future npa specifier types.

Source

Thrown at packages/angular/cli/src/package-managers/package-manager.ts:642

          const { dependencies } = JSON.parse(tempManifest) as PackageManifest;
          const packageName = dependencies && Object.keys(dependencies)[0];

          if (!packageName) {
            throw new Error(`Could not determine package name for specifier: ${specifier}`);
          }

          // The package will be installed in `<temp>/node_modules/<name>`.
          const packagePath = join(workingDirectory, 'node_modules', packageName);
          const manifestPath = join(packagePath, 'package.json');
          const manifest = await this.host.readFile(manifestPath);

          return JSON.parse(manifest);
        } finally {
          await cleanup();
        }
      }
      default:
        throw new Error(`Unsupported package specifier type: ${type}`);
    }
  }

  private async getTemporaryDirectory(): Promise<string | undefined> {
    const { tempDirectory } = this.options;

    if (tempDirectory && !relative(this.cwd, tempDirectory).startsWith('..')) {
      try {
        await this.host.stat(tempDirectory);
      } catch {
        // If the cache directory doesn't exist, create it.
        await this.host.mkdir(tempDirectory, { recursive: true });
      }

      return tempDirectory;
    }

    const tempOptions = ['node_modules'];

View on GitHub (pinned to bb72145f9a)

Solutions

  1. Log/print npa(specifier) to see the resolved type and rewrite the specifier into a supported form (registry range, tag, directory, file, remote tarball, or git URL).
  2. If passing an npa.Result programmatically, normalize its `type` to one of the supported values before calling getManifest.
  3. Align the npa version used by your tooling with the one bundled by @angular/cli to avoid classification differences.
  4. Fetch the manifest directly from the registry yourself as a fallback if the specifier cannot be expressed in a supported form.

Example fix

// before
await pm.getManifest({ name: 'x', type: 'unknown', fetchSpec: 'x' } as npa.Result);
// after
await pm.getManifest('x@^1.0.0');
Defensive patterns

Strategy: type-guard

Validate before calling

import npa from 'npm-package-arg';
const SUPPORTED = new Set(['range', 'version', 'tag', 'directory', 'file', 'remote', 'git']);
const r = npa(specifier);
if (!SUPPORTED.has(r.type)) {
  throw new Error(`Unsupported specifier type '${r.type}' for '${specifier}'`);
}

Type guard

const SUPPORTED_TYPES = ['range', 'version', 'tag', 'directory', 'file', 'remote', 'git'] as const;
type SupportedType = typeof SUPPORTED_TYPES[number];
function isSupportedType(t: string): t is SupportedType {
  return (SUPPORTED_TYPES as readonly string[]).includes(t);
}

Try / catch

try {
  const manifest = await pm.getManifest(specifier);
} catch (err) {
  if ((err as Error).message.startsWith('Unsupported package specifier type')) {
    logger.error(`Rewrite '${specifier}' into a supported form (name@version, path, or URL)`);
  } else throw err;
}

Prevention

When it happens

Trigger: getManifest called with a specifier string that npa classifies as an exotic type — practically rare, but possible via manually constructed npa.Result objects with a custom/unsupported `type` field, or unexpected npa version behavior on odd inputs.

Common situations: Programmatic tooling passing pre-parsed npa.Result objects with nonstandard types, npa version mismatches changing classification of edge-case specifiers, or alias/other specifier forms not covered by the switch.

Related errors


AI-assisted analysis of angular/angular-cli@bb72145f9a (2026-08-30). Data as JSON: /api/errors/9a40d1a68a2ab442. Report an issue: GitHub.