Yeachan-Heo/oh-my-codex · error · Error

[ask] --agent-prompt role "${normalizedRole}" not found in $

Error message

[ask] --agent-prompt role "${normalizedRole}" not found in ${promptsDir}.${availableSuffix}

What it means

The prompts directory exists but contains no `<role>.md` file for the requested role. The error lists available roles (all .md filenames minus extension, sorted) so the user can immediately pick a valid one.

Source

Thrown at src/cli/ask.ts:80

  if (!SAFE_ROLE_PATTERN.test(normalizedRole)) {
    throw new Error(`[ask] invalid --agent-prompt role "${role}". Expected lowercase role names like "executor" or "test-engineer".`);
  }

  if (!existsSync(promptsDir)) {
    throw new Error(`[ask] prompts directory not found: ${promptsDir}. Run "omx setup" to install prompts.`);
  }

  const promptPath = join(promptsDir, `${normalizedRole}.md`);
  if (!existsSync(promptPath)) {
    const files = await readdir(promptsDir).catch(() => [] as string[]);
    const availableRoles = files
      .filter((file) => file.endsWith('.md'))
      .map((file) => file.slice(0, -3))
      .sort();
    const availableSuffix = availableRoles.length > 0
      ? ` Available roles: ${availableRoles.join(', ')}.`
      : '';
    throw new Error(`[ask] --agent-prompt role "${normalizedRole}" not found in ${promptsDir}.${availableSuffix}`);
  }

  const content = (await readFile(promptPath, 'utf-8')).trim();
  if (!content) {
    throw new Error(`[ask] --agent-prompt role "${normalizedRole}" is empty: ${promptPath}`);
  }

  return content;
}

export function parseAskArgs(args: readonly string[]): ParsedAskArgs {
  const [providerRaw, ...rest] = args;
  const provider = (providerRaw || '').toLowerCase();

  if (!provider || !ASK_PROVIDER_SET.has(provider)) {
    throw askUsageError(`Invalid provider "${providerRaw || ''}". Expected one of: ${ASK_PROVIDERS.join(', ')}.`);
  }

View on GitHub (pinned to 3ad79a8a6f)

Solutions

  1. Pick from the 'Available roles:' list printed in the error message
  2. Check for the exact file: `ls <promptsDir>` and use the basename without .md
  3. Update to a version that ships the role you need, or create `<role>.md` in the prompts dir yourself
  4. Fix typos in the role name

Example fix

# before
omx ask --agent-prompt architech "task"
# after
omx ask --agent-prompt executor "task"
Defensive patterns

Strategy: validation

Validate before calling

import { existsSync, readdirSync } from 'node:fs';
const available = readdirSync(promptsDir).filter(f => f.endsWith('.md')).map(f => f.slice(0,-3));
if (!available.includes(role)) throw new Error(`role '${role}' not in ${available.join(', ')}`);

Type guard

const isKnownRole = (roles: string[]) => (r: string): r is string => roles.includes(r);

Try / catch

catch (e) { const m = /Available roles: (.+)\./.exec(String(e)); if (m) suggestRoles(m[1].split(', ')); else throw e; }

Prevention

When it happens

Trigger: Passing `--agent-prompt architect` when only executor.md and test-engineer.md exist in the prompts directory; renamed prompt files; stale role names after prompt set changes.

Common situations: Role renamed between omx versions; team-specific prompt sets that don't include the requested role; typos in the role name that still pass the safe-character regex.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27). Data as JSON: /api/errors/2414dc90098b7b32. Report an issue: GitHub.