{"record":{"id":"9bc227d3a84dc1b8","repo":"Yeachan-Heo/oh-my-codex","slug":"invalid-agenttypes-entries-invalid-join","errorCode":null,"errorMessage":"Invalid agentTypes entries: ${invalid.join(', ')}. Expected codex|claude|gemini.","messagePattern":"Invalid agentTypes entries: (.+?)\\. Expected codex\\|claude\\|gemini\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/team/runtime-cli.ts","lineNumber":218,"sourceCode":"  workerCount: number,\n  startTimeMs: number,\n): TerminalCliResult {\n  const status = phase === 'complete' ? 'completed' : 'failed';\n  return {\n    output: buildCliOutput(stateRoot, teamName, status, workerCount, startTimeMs),\n    exitCode: status === 'completed' ? 0 : 1,\n    notice:\n      `[runtime-cli] phase=${phase} reached terminal state; preserving team state for inspection. `\n      + `Inspect with \"omx team status ${teamName} --json\" or \"omx team api read-stall-state --input '{\\\"team_name\\\":\\\"${teamName}\\\"}' --json\". `\n      + `Run \"omx team shutdown ${teamName}\" (or --force after state capture) when explicit cleanup is desired.\\n`,\n  };\n}\n\nexport function normalizeAgentTypes(raw: string[], workerCount: number): TeamWorkerProvider[] {\n  const providers = raw.map((entry) => String(entry || '').trim().toLowerCase());\n  const invalid = providers.filter((entry) => entry !== 'codex' && entry !== 'claude' && entry !== 'gemini');\n  if (invalid.length > 0) {\n    throw new Error(`Invalid agentTypes entries: ${invalid.join(', ')}. Expected codex|claude|gemini.`);\n  }\n  if (providers.length !== 1 && providers.length !== workerCount) {\n    throw new Error(`agentTypes length must be 1 or ${workerCount}; received ${providers.length}.`);\n  }\n  return providers as TeamWorkerProvider[];\n}\n\nexport function resolveRuntimeCliProviderMap(\n  raw: string[] | undefined,\n  workerCount: number,\n): string | null {\n  if (!Array.isArray(raw) || raw.length === 0) {\n    return null;\n  }\n  return normalizeAgentTypes(raw, workerCount).join(',');\n}\n\nexport function resolveRuntimeCliAgentType(raw: string | undefined): string {","sourceCodeStart":200,"sourceCodeEnd":236,"githubUrl":"https://github.com/Yeachan-Heo/oh-my-codex/blob/3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2/src/team/runtime-cli.ts#L200-L236","documentation":"normalizeAgentTypes validates the --agentTypes-style array: after trim/lowercase, every entry must be exactly 'codex', 'claude', or 'gemini'. Any other string (including empty strings, provider names with typos like 'claude-code' or 'gpt') makes the invalid list non-empty and throws. The message lists the offending entries.","triggerScenarios":"Calling normalizeAgentTypes(['gpt4']) or passing a CLI-provided --agentTypes value like 'codex,openai'; also an empty string entry from a trailing comma split.","commonSituations":"Typos in CLI flags, provider names from an older version (new provider added/renamed), or naive string splitting of a comma-joined list producing empty entries.","solutions":["Correct entries to codex|claude|gemini (exact, lowercase; input is lowercased for you)","Trim and filter empty strings when splitting a joined CLI value before calling","Check for renamed providers in release notes if the value used to work"],"exampleFix":"// before\nconst providers = normalizeAgentTypes(userArg.split(','), workerCount);\n// after\nconst providers = normalizeAgentTypes(userArg.split(',').map(s => s.trim()).filter(Boolean), workerCount);","handlingStrategy":"validation","validationCode":"const VALID = new Set(['codex','claude','gemini']);\nconst cleaned = raw.map(s => s.trim().toLowerCase()).filter(Boolean);\nif (!cleaned.every(s => VALID.has(s))) throw new Error(`unsupported provider; valid: ${[...VALID].join('|')}`);","typeGuard":"const isProvider = (s: string): s is TeamWorkerProvider => ['codex','claude','gemini'].includes(s.trim().toLowerCase());","tryCatchPattern":"try { normalizeAgentTypes(raw, n); } catch (e) { if (e instanceof Error && e.message.startsWith('Invalid agentTypes')) { /* prompt user with valid options */ } throw e; }","preventionTips":["Filter empty strings after splitting comma-joined CLI values","Lowercase/trim user input before validation","Keep provider allowlist in one shared constant"],"tags":["cli-validation","enum-validation","agent-providers"],"backgroundTag":"enum-value-validation-failed","analyzedSha":"3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2","analyzedAt":"2026-08-27T22:18:39.783Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}