Skip to content

fix(@angular/cli): gracefully skip unfetchable packages during ng update#32928

Open
maruthang wants to merge 2 commits intoangular:mainfrom
maruthang:fix-28834-ng-update-private-packages
Open

fix(@angular/cli): gracefully skip unfetchable packages during ng update#32928
maruthang wants to merge 2 commits intoangular:mainfrom
maruthang:fix-28834-ng-update-private-packages

Conversation

@maruthang
Copy link
Copy Markdown
Contributor

Problem

ng update hard-fails when package.json contains packages that pass
the isPkgFromRegistry check (i.e., they are specified as plain semver
ranges) but cannot actually be fetched from the registry. This affects
JSR packages (@std/toml), private/scoped packages on corporate
registries (AWS CodeArtifact), and local workspace packages referenced
by name. The error looks like:

Migration failed: 404 Not Found - GET https://registry.npmjs.org/@std%2ftoml - Not found

Root Cause

In packages/angular/cli/src/commands/update/schematic/index.ts, all
package metadata is fetched via Promise.all(deps.map(getNpmPackageJson)).
If any single fetch rejects (404, ENOTFOUND, auth error), the entire
Promise.all rejects and kills the update before any package is
processed.

The code that follows the Promise.all already handles the "package not
found" case gracefully (it distinguishes between auto-discovered packages
and explicitly-requested ones), but it never gets a chance to run when
the fetch itself throws.

Fix

Attach a .catch() to each individual getNpmPackageJson call. On
failure the catch emits a warning like:

Package '@std/toml' could not be fetched from the registry: 404 Not Found ...

and returns the same sentinel shape ({ requestedName }) that the
existing reduce block already knows how to handle:

  • Auto-discovered dependencies (not passed on the CLI): skipped with a warning, rest of update continues.
  • Explicitly requested packages (ng update @some/pkg): still produce a SchematicsException so the user gets a clear error.

New Behavior

$ ng update
Package '@std/toml' could not be fetched from the registry: 404 Not Found - GET https://registry.npmjs.org/@std%2ftoml - Not found
We analyzed your package.json, there are some packages to update: ...

Instead of:

Migration failed: 404 Not Found - GET https://registry.npmjs.org/@std%2ftoml - Not found

Test

Added a regression test in index_spec.ts that puts a non-existent
scoped package (@private-nonexistent/package-ng-update-issue-28834)
alongside a real one, runs the schematic, and asserts it completes
without throwing while emitting a warning for the unfetchable package.

Closes #28834

When package.json contains packages from non-npmjs registries (JSR, AWS
CodeArtifact, private registries, local workspace packages), the registry
fetch inside Promise.all would reject and hard-fail the entire update
command with a 404 or network error.

Wrap each per-package getNpmPackageJson call in a .catch() so that fetch
failures emit a warning and return a partial sentinel object. The existing
reduce step already handles partial objects correctly: auto-discovered
packages are silently skipped while explicitly-requested packages still
produce a clear SchematicsException, preserving intentional error
visibility.

Closes angular#28834
Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces error handling for package fetching in the Angular CLI update schematic, allowing the process to continue with a warning if a package cannot be retrieved from a registry. This change improves support for private registries and local workspace packages that might otherwise cause the update to fail. The review feedback suggests making the error message extraction more robust to handle non-Error objects and enhancing the regression test to ensure it verifies that other packages are successfully updated when a fetch failure occurs.

// If the package cannot be fetched (e.g. private registry, JSR, AWS CodeArtifact,
// or local workspace packages), return a partial object so the reduce below can
// decide whether to warn or hard-fail based on whether it was explicitly requested.
const message = error instanceof Error ? error.message : String(error);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The error message extraction could be more robust. If error is a plain object with a message property (which can happen with some HTTP clients or custom errors), instanceof Error will be false and String(error) will result in [object Object]. Consider using a fallback to the .message property if it exists to provide a more helpful warning.

Suggested change
const message = error instanceof Error ? error.message : String(error);
const message = error instanceof Error ? error.message : (error as any)?.message ?? String(error);

expect(resultTreeContent.endsWith('}')).toBeTrue();
});

it('skips packages that cannot be fetched from the registry and continues updating others', async () => {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The test case name indicates that it verifies the schematic 'continues updating others', but the current implementation only verifies that the analysis phase completes without throwing when no packages are requested for update. To fully validate the intended behavior, consider requesting an update for a valid package (e.g., @angular-devkit-tests/update-base) and asserting that it is successfully updated despite the fetch failure of the other package.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ng update breaks on "private" packages

1 participant