Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions packages/angular/cli/src/commands/update/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,12 @@ import {
Options,
} from '../../command-builder/command-module';
import { SchematicEngineHost } from '../../command-builder/utilities/schematic-engine-host';
import type { InstalledPackage, PackageManager, PackageManifest } from '../../package-managers';
import {
type InstalledPackage,
type PackageManager,
PackageManagerError,
type PackageManifest,
} from '../../package-managers';
import { colors } from '../../utilities/color';
import { disableVersionCheck } from '../../utilities/environment-options';
import { assertIsError } from '../../utilities/error';
Expand Down Expand Up @@ -596,7 +601,16 @@ export default class UpdateCommandModule extends CommandModule<UpdateCommandArgs
ignorePeerDependencies,
});
} catch (e) {
throw new CommandError('Unable to install packages');
assertIsError(e);
let message = `Unable to install packages: ${colors.bold(e.message)}`;
if (e instanceof PackageManagerError) {
const stdout = e.stdout?.trim();
const stderr = e.stderr?.trim();
if (stdout) message += `\n\n${colors.bold('[STDOUT]')}: ${stdout}`;
if (stderr) message += `\n\n${colors.bold('[STDERR]')}: ${stderr}`;
}

throw new CommandError(message);
}
Comment on lines 603 to 614

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

  1. Defensive Programming: If e.stdout or e.stderr is undefined or null at runtime (e.g., in certain error scenarios or test environments), calling .trim() directly on them will throw a TypeError (e.g., Cannot read properties of undefined (reading 'trim')). This would crash the CLI and completely mask the original package manager error. Using optional chaining (?.) and nullish coalescing (??) prevents this secondary crash.

  2. Preserving Non-PackageManagerError Context: If e is not an instance of PackageManagerError (e.g., a network failure, file system issue, or other unexpected error), the current implementation discards the original error message and throws a generic 'Unable to install packages' message. Appending the original error's message using assertIsError(e) ensures that valuable diagnostic context is not lost.

          } catch (e) {
            let message = 'Unable to install packages';
            if (e instanceof PackageManagerError) {
              const stdout = e.stdout?.trim() ?? '';
              const stderr = e.stderr?.trim() ?? '';
              message += `: ${colors.bold(e.message)}${
                stdout ? `\n\n${colors.bold('[STDOUT]')}: ${stdout}` : ''
              }${stderr ? `\n\n${colors.bold('[STDERR]')}: ${colors.red(stderr)}` : ''}`;
            } else {
              assertIsError(e);
              message += `: ${e.message}`;
            }

            throw new CommandError(message);
          }

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Updated to always propagate errors and use assertIsError as suggested. @alan-agius4 can you confirm that assertIsError is appropriate? The assertion error would still surface an error, but would not include "Update to install packages". I assume the assertion error is unlikely to be triggered because the codebase probably consistently uses error objects rather than primitive types / non error objects.

},
},
Expand Down
Loading