angular/angular-cli · warning

Package specifier has no effect when using "migrate-only" op

Error message

Package specifier has no effect when using "migrate-only" option.

What it means

When `ng update --migrate-only` is used, no packages are actually updated — only migrations run — so any package specifier (like a version range) supplied on the command line has no effect. The CLI logs this warning and continues, unless the specifier is the implicit wildcard '*' (no specifier given).

Source

Thrown at packages/angular/cli/src/commands/update/cli.ts:211

    for (const request of options.packages ?? []) {
      try {
        const packageIdentifier = npa(request);

        // only registry identifiers are supported
        if (!packageIdentifier.registry) {
          logger.error(`Package '${request}' is not a registry package identifer.`);

          return 1;
        }

        if (packages.some((v) => v.name === packageIdentifier.name)) {
          logger.error(`Duplicate package '${packageIdentifier.name}' specified.`);

          return 1;
        }

        if (options.migrateOnly && packageIdentifier.rawSpec !== '*') {
          logger.warn('Package specifier has no effect when using "migrate-only" option.');
        }

        // Wildcard uses the next tag if next option is used otherwise use latest tag.
        // Wildcard is present if no selector is provided on the command line.
        if (packageIdentifier.rawSpec === '*') {
          packageIdentifier.fetchSpec = options.next ? 'next' : 'latest';
          packageIdentifier.type = 'tag';
        }

        packages.push(packageIdentifier);
      } catch (e) {
        assertIsError(e);
        logger.error(e.message);

        return 1;
      }
    }

View on GitHub (pinned to bb72145f9a)

Solutions

  1. Remove the package specifier: run `ng update @angular/core --migrate-only` (or just `ng update --migrate-only`) so no meaningless selector is passed.
  2. If you actually want the package updated too, drop --migrate-only and run a normal `ng update @angular/core@<version>`.
  3. Update scripts/CI configs to strip version selectors from migrate-only invocations.

Example fix

// before
ng update @angular/core@16 --migrate-only
// after
ng update @angular/core --migrate-only
Defensive patterns

Strategy: validation

Validate before calling

const args = ['ng', 'update', ...pkgs];
if (migrateOnly) {
  // strip version selectors when migrate-only
  args.splice(args.indexOf('@angular/core@16'), 1, '@angular/core');
}

Try / catch

if (migrateOnly && pkgSpecifier !== '*') {
  logger.warn('Specifier ignored with --migrate-only; dropping it');
  pkgSpecifier = undefined;
}

Prevention

When it happens

Trigger: Running e.g. `ng update @angular/core@16 --migrate-only` (or any non-'*' rawSpec) so the condition `options.migrateOnly && packageIdentifier.rawSpec !== '*'` is true.

Common situations: Copy-pasting an update command and appending --migrate-only to run only migrations; scripting migrate-only runs while retaining version selectors from previous full-update commands.

Related errors


AI-assisted analysis of angular/angular-cli@bb72145f9a (2026-08-30). Data as JSON: /api/errors/f40657a4f4ed0d3c. Report an issue: GitHub.