can1357/oh-my-pi · error · CliUsageError

Unknown tool${unknown.length === 1 ? "" : "s"} in --tools: $

Error message

Unknown tool${unknown.length === 1 ? "" : "s"} in --tools: ${unknown.join(", ")}. Valid tools: ${known.join(", ")}.

What it means

validateToolNames filters the requested --tools names against the fully discovered session tool registry and throws a CliUsageError listing the unrecognized names plus all valid tool names, when any requested tool does not exist.

Source

Thrown at packages/coding-agent/src/cli/args.ts:341

	for (const trustedPath of result.trustedExtensions ?? []) {
		if (trustedPath.length === 0) {
			throw new CliUsageError("--trusted-extension requires a non-empty, non-flag value");
		}
		if (!path.isAbsolute(trustedPath)) {
			throw new CliUsageError(`--trusted-extension requires an absolute path: ${trustedPath}`);
		}
	}

	return result;
}

/** Reject requested tool names absent from the fully discovered session registry. */
export function validateToolNames(requested: readonly string[] | undefined, known: readonly string[]): void {
	if (!requested) return;
	const knownNames = new Set(known);
	const unknown = requested.filter(name => !knownNames.has(name));
	if (unknown.length === 0) return;
	throw new CliUsageError(
		`Unknown tool${unknown.length === 1 ? "" : "s"} in --tools: ${unknown.join(", ")}. Valid tools: ${known.join(", ")}.`,
	);
}

/**
 * Emit a stderr error listing the unrecognized flags and return `true` when
 * there were any. Caller is expected to exit with a non-zero status. Splitting
 * the print from the exit keeps the helper unit-testable without forking a
 * process (issue #2459).
 */
export function reportUnrecognizedFlags(
	args: Pick<Args, "unrecognizedFlags">,
	write: (text: string) => void = text => process.stderr.write(text),
): boolean {
	if (args.unrecognizedFlags.length === 0) return false;
	const flags = args.unrecognizedFlags;
	const plural = flags.length === 1 ? "" : "s";
	write(`${chalk.red(`Error: unknown flag${plural}: ${flags.join(", ")}`)}\n`);

View on GitHub (pinned to 9690622007)

Solutions

  1. Fix the tool names listed as unknown, using the 'Valid tools:' list in the message.
  2. Run with --tools omitted (or list tools via the CLI) to see the current registry.
  3. If the tool comes from an extension/MCP server, ensure that server is enabled in this session.
  4. Pin the omp version in scripts so tool names match the documented set.

Example fix

// before
omp --tools read,edit,bash_it
// after
omp --tools read,edit,bash
Defensive patterns

Strategy: validation

Validate before calling

// discover the registry first, then filter before invoking
const known = await discoverToolNames(); // e.g. from session registry
const requested = ["read", "edit", "bash_it"];
const bad = requested.filter(n => !known.includes(n));
if (bad.length) throw new Error(`Remove unknown tools: ${bad.join(", ")}`);

Type guard

null

Try / catch

try {
  await runRootCommand(argv);
} catch (err) {
  if (err instanceof CliUsageError && err.message.startsWith("Unknown tool")) {
    console.error(err.message); // lists valid tools
    process.exitCode = 2;
    return;
  }
  throw err;
}

Prevention

When it happens

Trigger: Passing `--tools` with one or more names absent from the registry: typos (read vs read_file), renamed tools after an upgrade, or tools only present via extensions/MCP that are not loaded in this session.

Common situations: Upgrading omp where a tool was renamed; writing scripts against another machine's tool set; referencing MCP-provided tools before the MCP server is configured.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/00d309c6eea47733. Report an issue: GitHub.