{"record":{"id":"4397d687d0f660fe","repo":"angular/angular-cli","slug":"invalid-option-key-key-option-keys-must-be","errorCode":null,"errorMessage":"Invalid option key: '${key}'. Option keys must be alphanumeric, hyphens, or underscores.","messagePattern":"Invalid option key: '(.+?)'\\. Option keys must be alphanumeric, hyphens, or underscores\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/angular/cli/src/commands/mcp/tools/run-target/options-serializer.ts","lineNumber":30,"sourceCode":" * Serializes a Zod-validated options record into standard CLI argument flags.\n * Enforces strict regex validation on option keys to prevent flag manipulation.\n */\nexport function serializeOptions(\n  options: Record<string, OptionValue> | undefined,\n  excludeKeys: Set<string> = new Set(),\n): string[] {\n  const args: string[] = [];\n  if (!options) {\n    return args;\n  }\n\n  for (const [key, value] of Object.entries(options)) {\n    if (excludeKeys.has(key)) {\n      continue;\n    }\n\n    if (!/^[a-zA-Z0-9-_]+$/.test(key)) {\n      throw new Error(\n        `Invalid option key: '${key}'. Option keys must be alphanumeric, hyphens, or underscores.`,\n      );\n    }\n\n    if (typeof value === 'boolean') {\n      args.push(value ? `--${key}` : `--no-${key}`);\n    } else if (Array.isArray(value)) {\n      for (const item of value) {\n        args.push(`--${key}=${item}`);\n      }\n    } else if (value !== null && value !== undefined) {\n      args.push(`--${key}=${value}`);\n    }\n  }\n\n  return args;\n}\n","sourceCodeStart":12,"sourceCodeEnd":48,"githubUrl":"https://github.com/angular/angular-cli/blob/bb72145f9ab45aee29f523236b3a25cd0813a841/packages/angular/cli/src/commands/mcp/tools/run-target/options-serializer.ts#L12-L48","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nrunTarget({ target: 'build', options: { 'output.path': 'dist/x' } });\n// after\nrunTarget({ target: 'build', options: { 'output-path': 'dist/x' } });","handlingStrategy":"validation","validationCode":"const VALID_KEY = /^[a-zA-Z0-9-_]+$/;\nfor (const key of Object.keys(options)) {\n  if (!VALID_KEY.test(key)) {\n    throw new Error(`Invalid option key: ${key}`);\n  }\n}","typeGuard":"function hasValidOptionKeys(o: Record<string, unknown>): o is Record<string, unknown> {\n  return Object.keys(o).every((k) => /^[a-zA-Z0-9-_]+$/.test(k));\n}","tryCatchPattern":"try {\n  await runTarget(input);\n} catch (e) {\n  if ((e as Error).message.startsWith('Invalid option key')) {\n    console.error('Fix the option key: use only letters, digits, hyphens, underscores');\n  } else throw e;\n}","preventionTips":["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"],"tags":["validation","cli-options","injection-prevention","angular-cli"],"backgroundTag":"schema-validation-failed","analyzedSha":"bb72145f9ab45aee29f523236b3a25cd0813a841","analyzedAt":"2026-08-30T02:47:34.745Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}