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
- Rename the option key to contain only letters, digits, hyphens, or underscores
- Strip or transform keys before passing (e.g. map 'tsconfig.json' to a supported flag name)
- Check the Angular CLI schema for the target to find the correct flag spelling
- 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
- Derive option keys from the target's Angular CLI schema, not free-form JSON
- Sanitize/normalize keys (kebab-case, no dots) before passing options
- Add a schema validation step on the options object before tool calls
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
- Invalid config found at ${workspace.filePath}. CLI should be
- Invalid value for argument: ${key}, Given: '${pair}', Expect
- --from requires that only a single package be passed.
- Could not parse package name from specifier: ${specifier}
- Invalid collection.json; schematics needs to be an object.
AI-assisted analysis of angular/angular-cli@bb72145f9a (2026-08-30).
Data as JSON: /api/errors/4397d687d0f660fe.
Report an issue: GitHub.