angular/angular-cli · error · CommandModuleError

Option --registry must be a valid URL.

Error message

Option --registry must be a valid URL.

What it means

The 'ng add' command validates its --registry option with a yargs coerce/check that requires the value to be a string parseable by URL.canParse. If a string registry is passed that is not a valid absolute URL (e.g. missing scheme), a CommandModuleError 'Option --registry must be a valid URL.' is thrown before any install work starts.

Source

Thrown at packages/angular/cli/src/commands/add/cli.ts:139

        default: false,
      })
      .option('skip-confirmation', {
        description:
          'Skip asking a confirmation prompt before installing and executing the package. ' +
          'Ensure package name is correct prior to using this option.',
        type: 'boolean',
        default: false,
      })
      .check(({ registry }) => {
        if (registry === undefined) {
          return true;
        }

        if (typeof registry === 'string' && URL.canParse(registry)) {
          return true;
        }

        throw new CommandModuleError('Option --registry must be a valid URL.');
      })
      // Prior to downloading we don't know the full schema and therefore we cannot be strict on the options.
      // Possibly in the future update the logic to use the following syntax:
      // `ng add @angular/localize -- --package-options`.
      .strict(false);

    const collectionName = this.getCollectionName();
    if (!collectionName) {
      return localYargs;
    }

    const workflow = this.getOrCreateWorkflowForBuilder(collectionName);

    try {
      const collection = workflow.engine.createCollection(collectionName);
      const options = await this.getSchematicOptions(collection, this.schematicName, workflow);

      return this.addSchemaOptionsToCommand(localYargs, options);

View on GitHub (pinned to bb72145f9a)

Solutions

  1. Pass a fully-qualified URL: 'ng add @scope/pkg --registry https://registry.npmjs.org'.
  2. Add the scheme for local registries: 'http://localhost:4873' instead of 'localhost:4873'.
  3. If the registry comes from a variable/script, validate it with new URL(value) before invoking ng add.
  4. Alternatively configure the registry in .npmrc (registry=...) so --registry is not needed.

Example fix

// before
ng add @angular/localize --registry localhost:4873

// after
ng add @angular/localize --registry http://localhost:4873
Defensive patterns

Strategy: validation

Validate before calling

function isValidRegistryUrl(value) {
  return typeof value === 'string' && URL.canParse(value);
}
const registry = process.argv[/* ... */];
if (!isValidRegistryUrl(registry)) {
  throw new Error(`--registry must be an absolute URL, got: ${registry}`);
}

Type guard

function isHttpUrl(value: unknown): value is string {
  if (typeof value !== 'string' || !URL.canParse(value)) return false;
  const { protocol } = new URL(value);
  return protocol === 'http:' || protocol === 'https:';
}

Try / catch

try {
  await runNgAdd(pkg, { registry });
} catch (e) {
  if (e instanceof CommandModuleError && e.message.includes('--registry must be a valid URL')) {
    console.error(`Invalid registry '${registry}'. Use e.g. https://registry.npmjs.org`);
  } else { throw e; }
}

Prevention

When it happens

Trigger: Running 'ng add <package> --registry <value>' where <value> is a string that URL.canParse rejects — e.g. 'localhost:4873', 'my-registry.local', 'http:/wrong', or an empty string.

Common situations: Pointing ng add at a local npm proxy like Verdaccio and passing the host without the 'http://' scheme; copy-pasting a registry value from .npmrc without the protocol; shell mangling of '//' in URLs.

Related errors


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