angular/angular-cli · error · Error

Invalid option key: '${key}'. Option keys must be alphanumer

Error message

Invalid option key: '${key}'. Option keys must be alphanumeric, hyphens, or underscores.

What it means

serializeOptions converts an options object into CLI argument strings. Because option keys are interpolated directly into shell-like arguments, each key is validated against /^[a-zA-Z0-9-_]+$/; a key containing any other character (spaces, dots, slashes, '=' etc.) is rejected to prevent argument injection or malformed flags.

Source

Thrown at packages/angular/cli/src/commands/mcp/tools/run-target/options-serializer.ts:30

 * Serializes a Zod-validated options record into standard CLI argument flags.
 * Enforces strict regex validation on option keys to prevent flag manipulation.
 */
export function serializeOptions(
  options: Record<string, OptionValue> | undefined,
  excludeKeys: Set<string> = new Set(),
): string[] {
  const args: string[] = [];
  if (!options) {
    return args;
  }

  for (const [key, value] of Object.entries(options)) {
    if (excludeKeys.has(key)) {
      continue;
    }

    if (!/^[a-zA-Z0-9-_]+$/.test(key)) {
      throw new Error(
        `Invalid option key: '${key}'. Option keys must be alphanumeric, hyphens, or underscores.`,
      );
    }

    if (typeof value === 'boolean') {
      args.push(value ? `--${key}` : `--no-${key}`);
    } else if (Array.isArray(value)) {
      for (const item of value) {
        args.push(`--${key}=${item}`);
      }
    } else if (value !== null && value !== undefined) {
      args.push(`--${key}=${value}`);
    }
  }

  return args;
}

View on GitHub (pinned to bb72145f9a)

Solutions

  1. Rename the option key to contain only letters, digits, hyphens, or underscores
  2. Strip or transform keys before passing (e.g. map 'tsconfig.json' to a supported flag name)
  3. Check the Angular CLI schema for the target to find the correct flag spelling
  4. If the value is meant as a positional/config value rather than a flag, pass it through the appropriate input field instead of options

Example fix

// before
runTarget({ target: 'build', options: { 'output.path': 'dist/x' } });
// after
runTarget({ target: 'build', options: { 'output-path': 'dist/x' } });
Defensive patterns

Strategy: validation

Validate before calling

const VALID_KEY = /^[a-zA-Z0-9-_]+$/;
for (const key of Object.keys(options)) {
  if (!VALID_KEY.test(key)) {
    throw new Error(`Invalid option key: ${key}`);
  }
}

Type guard

function hasValidOptionKeys(o: Record<string, unknown>): o is Record<string, unknown> {
  return Object.keys(o).every((k) => /^[a-zA-Z0-9-_]+$/.test(k));
}

Try / catch

try {
  await runTarget(input);
} catch (e) {
  if ((e as Error).message.startsWith('Invalid option key')) {
    console.error('Fix the option key: use only letters, digits, hyphens, underscores');
  } else throw e;
}

Prevention

When it happens

Trigger: Calling the run_target MCP tool with an options object whose key contains characters outside [a-zA-Z0-9-_], e.g. { 'output-path': 'x' } is fine but { 'output path': 'x' }, { 'tsconfig.json': true } or { 'a=b': true } throw at options-serializer.ts:30. Excluded keys (via excludeKeys) are skipped before validation.

Common situations: Passing file names with dots as option keys; camelCase vs flag confusion leading users to embed dots or spaces; forwarding raw JSON config entries whose keys were not designed as CLI flags.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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