Skip to content

ng add fails to detect schematics on first run with private package registries #33060

@jsskeen-utah

Description

@jsskeen-utah

Disclaimer: while I did use AI to help me investigate and write up this issue, this is 100% a real problem that has caused me to lose sleep while debugging at work.

Command

add

Is it a regression?

Unknown - We cannot confirm whether this used to work as we don't have access to older CLI versions paired with older private package versions on GitHub Packages to test with

Description:

When running ng add with a package that provides schematics (via schematics and ng-add fields in package.json), the Angular CLI fails to detect and execute the schematics on the first attempt. The CLI reports "The package does not provide any ng add actions" even though the package does include schematics.

On subsequent runs of ng add (when the package is already installed), the schematics are correctly detected and executed.

This issue occurs because the CLI uses two different code paths with different rules to determine if schematics exist: one path queries the registry metadata, while another (when the package is already installed) uses the filesystem directly. When a registry doesn't expose the schematics field in its metadata API, the first path incorrectly fails.

Steps to Reproduce

  1. Create a new Angular application:

    ng new test-app --skip-install
    cd test-app
    npm install
  2. Add a package with ng-add schematics from a private GitHub Packages registry:

    ng add @scope/private-package-name@version
  3. Observe output (first run - FAILS to detect schematics):

    ✔ Determining Package Manager
      Using package manager: npm
    ✔ Loading package information
    ✔ Confirming installation
    ✔ Installing package
    Package installed successfully. The package does not provide any `ng add` actions, so no further actions would be taken.
    
  4. Run the same command again:

    ng add @scope/private-package-name@version
  5. Observe correct behavior (second run - works):

    Skipping installation: Package already installed
    UPDATE package.json (1043 bytes)
    UPDATE src/app/app.config.ts (712 bytes)
    UPDATE angular.json (2334 bytes)
    ✔ Packages installed successfully.
    

Root Cause

The Angular CLI uses two different code paths that use different rules:

Path 1 (during installation): Queries registry metadata to set hasSchematics:

// Line 524
context.hasSchematics = !!manifest.schematics;

Path 2 (when already installed): Runs schematic directly from node_modules at lines 176-188, bypassing registry check.

When the registry (e.g., GitHub Packages) doesn't include the schematics field in metadata, Path 1 incorrectly reports no schematics exist, while Path 2 would find them.

Verification

The installed package contains schematics:

$ cat node_modules/@scope/private-package/package.json | jq '{schematics, "ng-add"}'
{
  "schematics": "./collection.json",
  "ng-add": { "save": "dependencies" }
}

But registry metadata (from GitHub Packages) has no schematics field:

$ npm view @scope/private-package@version --json --registry=https://npm.pkg.github.com | grep schematics
(empty)

Proposed Fix

The installed package's package.json should be authoritative. Verification at lines 248-261 should run regardless of registry metadata when the package is installed.

Exception / Error

Package installed successfully. The package does not provide any ng add actions, so no further actions would be taken.

Environment:

  • Angular CLI: 21.2.8 (and likely earlier versions)
  • Node.js: v22.22.2
  • Package Manager: npm
  • OS: Linux - Debian 13
  • Registry: GitHub Packages (npm.pkg.github.com)

Additional Context

This issue was discovered while using an Angular library with ng-add schematics published on GitHub Packages. Despite the package being published with all correct metadata (schematics and ng-add fields in package.json), the npm view query from GitHub Packages does not return these fields.

While it would be ideal if GitHub Packages properly exposed the schematics field in registry metadata, that is a separate concern. The core issue reported here is that the Angular CLI uses two different code paths with different rules to determine schematic existence, which is unintuitive and leads to confusing behavior where the same command must be run twice to succeed.

We also tried to write an integration test to prove that this bug existed, but we discovered that if the package is installed from the tarball used to npm publish instead of the remote package itself, it would always work. This is likely because it wouldn't take the code path of determining the schematic's existence based on registry metadata and instead inspected the package.json file inside the tarball after installation.

Related Code

Key files to examine:

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions