{"record":{"id":"9a40d1a68a2ab442","repo":"angular/angular-cli","slug":"unsupported-package-specifier-type-type","errorCode":null,"errorMessage":"Unsupported package specifier type: ${type}","messagePattern":"Unsupported package specifier type: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/angular/cli/src/package-managers/package-manager.ts","lineNumber":642,"sourceCode":"          const { dependencies } = JSON.parse(tempManifest) as PackageManifest;\n          const packageName = dependencies && Object.keys(dependencies)[0];\n\n          if (!packageName) {\n            throw new Error(`Could not determine package name for specifier: ${specifier}`);\n          }\n\n          // The package will be installed in `<temp>/node_modules/<name>`.\n          const packagePath = join(workingDirectory, 'node_modules', packageName);\n          const manifestPath = join(packagePath, 'package.json');\n          const manifest = await this.host.readFile(manifestPath);\n\n          return JSON.parse(manifest);\n        } finally {\n          await cleanup();\n        }\n      }\n      default:\n        throw new Error(`Unsupported package specifier type: ${type}`);\n    }\n  }\n\n  private async getTemporaryDirectory(): Promise<string | undefined> {\n    const { tempDirectory } = this.options;\n\n    if (tempDirectory && !relative(this.cwd, tempDirectory).startsWith('..')) {\n      try {\n        await this.host.stat(tempDirectory);\n      } catch {\n        // If the cache directory doesn't exist, create it.\n        await this.host.mkdir(tempDirectory, { recursive: true });\n      }\n\n      return tempDirectory;\n    }\n\n    const tempOptions = ['node_modules'];","sourceCodeStart":624,"sourceCodeEnd":660,"githubUrl":"https://github.com/angular/angular-cli/blob/bb72145f9ab45aee29f523236b3a25cd0813a841/packages/angular/cli/src/package-managers/package-manager.ts#L624-L660","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["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).","If passing an npa.Result programmatically, normalize its `type` to one of the supported values before calling getManifest.","Align the npa version used by your tooling with the one bundled by @angular/cli to avoid classification differences.","Fetch the manifest directly from the registry yourself as a fallback if the specifier cannot be expressed in a supported form."],"exampleFix":"// before\nawait pm.getManifest({ name: 'x', type: 'unknown', fetchSpec: 'x' } as npa.Result);\n// after\nawait pm.getManifest('x@^1.0.0');","handlingStrategy":"type-guard","validationCode":"import npa from 'npm-package-arg';\nconst SUPPORTED = new Set(['range', 'version', 'tag', 'directory', 'file', 'remote', 'git']);\nconst r = npa(specifier);\nif (!SUPPORTED.has(r.type)) {\n  throw new Error(`Unsupported specifier type '${r.type}' for '${specifier}'`);\n}","typeGuard":"const SUPPORTED_TYPES = ['range', 'version', 'tag', 'directory', 'file', 'remote', 'git'] as const;\ntype SupportedType = typeof SUPPORTED_TYPES[number];\nfunction isSupportedType(t: string): t is SupportedType {\n  return (SUPPORTED_TYPES as readonly string[]).includes(t);\n}","tryCatchPattern":"try {\n  const manifest = await pm.getManifest(specifier);\n} catch (err) {\n  if ((err as Error).message.startsWith('Unsupported package specifier type')) {\n    logger.error(`Rewrite '${specifier}' into a supported form (name@version, path, or URL)`);\n  } else throw err;\n}","preventionTips":["Check npa(specifier).type before calling getManifest when feeding programmatic specifiers","Keep npa versions consistent with @angular/cli to avoid classification drift","Normalize alias/custom specifiers to registry form upstream","Log the resolved npa.Result when errors occur to ease diagnosis"],"tags":["package-manager","specifier-parsing","npm"],"backgroundTag":"invalid-package-specifier","analyzedSha":"bb72145f9ab45aee29f523236b3a25cd0813a841","analyzedAt":"2026-08-30T02:47:34.745Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}