{"record":{"id":"c38d7c711fe1e0bf","repo":"angular/angular-cli","slug":"could-not-determine-package-name-for-specifier","errorCode":null,"errorMessage":"Could not determine package name for specifier: ${specifier}","messagePattern":"Could not determine package name for specifier: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/angular/cli/src/package-managers/package-manager.ts","lineNumber":628,"sourceCode":"        if (!fetchSpec) {\n          throw new Error(`Could not parse location from specifier: ${specifier}`);\n        }\n\n        // Caching is not supported for non-registry specifiers.\n        const { workingDirectory, cleanup } = await this.acquireTempPackage(fetchSpec, {\n          ...options,\n          ignoreScripts: true,\n        });\n\n        try {\n          // Discover the package name by reading the temporary `package.json` file.\n          // The package manager will have added the package to the `dependencies`.\n          const tempManifest = await this.host.readFile(join(workingDirectory, 'package.json'));\n          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> {","sourceCodeStart":610,"sourceCodeEnd":646,"githubUrl":"https://github.com/angular/angular-cli/blob/bb72145f9ab45aee29f523236b3a25cd0813a841/packages/angular/cli/src/package-managers/package-manager.ts#L610-L646","documentation":"Thrown by PackageManager.getManifest after installing a file/remote/git specifier into a temporary directory: the CLI reads the temp package.json expecting the installed package to appear in `dependencies`, but none exists. Without a package name it cannot locate `<temp>/node_modules/<name>/package.json` to read the real manifest.","triggerScenarios":"getManifest called with a file/remote/git specifier where the temporary install produces a package.json with an empty or missing `dependencies` object — e.g. installing a local directory specifier that resolves as a workspace/link rather than a packed dependency, or a package manager that records the dependency outside `dependencies`.","commonSituations":"Pointing getManifest at a local folder that gets symlinked instead of installed, using a package manager whose lock/install behavior omits dependencies entries, a corrupted or incomplete temp install due to network or script failures with ignoreScripts, or specifier types whose resolution skips dependency recording.","solutions":["Retry with an explicit tarball or git URL specifier so the package is packed and recorded under dependencies in the temp install.","Ensure the target package itself has a valid name in its package.json and installs normally (run `npm pack`/`npm install <specifier>` manually to confirm).","Clear any package-manager cache/state and retry to rule out a corrupted temp install.","If programmatic, pass a registry specifier ('name@version') instead so the name is known up front."],"exampleFix":"// before\nawait pm.getManifest('./some/local/dir'); // may not record a dependency\n// after\nawait pm.getManifest('https://registry.npmjs.org/@angular/cli/-/cli-17.0.0.tgz');","handlingStrategy":"try-catch","validationCode":"const r = npa(specifier);\nif (r.type === 'directory') {\n  const pkg = JSON.parse(fs.readFileSync(path.join(r.fetchSpec, 'package.json'), 'utf8'));\n  if (!pkg.name) throw new Error(`Package at ${r.fetchSpec} has no name`);\n}","typeGuard":"function isPackageManifest(v: unknown): v is PackageManifest & { dependencies: Record<string, string> } {\n  return typeof v === 'object' && v !== null &&\n    'dependencies' in v && typeof (v as any).dependencies === 'object' &&\n    Object.keys((v as any).dependencies).length > 0;\n}","tryCatchPattern":"try {\n  const manifest = await pm.getManifest(specifier);\n} catch (err) {\n  if ((err as Error).message.startsWith('Could not determine package name for specifier')) {\n    logger.error(`Install of '${specifier}' did not record a dependency; try a tarball URL`);\n  } else throw err;\n}","preventionTips":["Verify the target installs cleanly with `npm install <specifier>` in a scratch dir before automation","Prefer explicit tarball/git URL specifiers over local directories for manifest lookups","Ensure the target package.json has a valid \"name\" field","Retry once with bypassCache on transient install failures"],"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"}