can1357/oh-my-pi · error

Unknown rule: ${ruleName} Available: ${availableStr}

Error message

Unknown rule: ${ruleName}
Available: ${availableStr}

What it means

The rule:// protocol handler resolves internal URLs of the form rule://<name> to the markdown content of an active capability rule. Before resolving, it looks up the rule name in the list returned by getActiveRules(); if no rule with that exact name is registered, it throws this error listing all currently available rule names (or "none" if no rules are active). It is a lookup-failure error meaning the referenced rule does not exist or is not active in the current session.

Source

Thrown at packages/coding-agent/src/internal-urls/rule-protocol.ts:26

import type { InternalResource, InternalUrl, ProtocolHandler, UrlCompletion } from "./types";

export class RuleProtocolHandler implements ProtocolHandler {
	readonly scheme = "rule";
	readonly immutable = true;

	async resolve(url: InternalUrl): Promise<InternalResource> {
		const rules = getActiveRules();

		const ruleName = url.rawHost || url.hostname;
		if (!ruleName) {
			throw new Error("rule:// URL requires a rule name: rule://<name>");
		}

		const rule = rules.find(r => r.name === ruleName);
		if (!rule) {
			const available = rules.map(r => r.name);
			const availableStr = available.length > 0 ? available.join(", ") : "none";
			throw new Error(`Unknown rule: ${ruleName}\nAvailable: ${availableStr}`);
		}

		return {
			url: url.href,
			content: rule.content,
			contentType: "text/markdown",
			size: Buffer.byteLength(rule.content, "utf-8"),
			sourcePath: rule.path,
			notes: [],
		};
	}

	async complete(): Promise<UrlCompletion[]> {
		return getActiveRules().map(rule => ({
			value: rule.name,
			...(rule.description ? { description: rule.description } : {}),
		}));
	}

View on GitHub (pinned to 9690622007)

Solutions

  1. Read the 'Available:' line in the error message and use one of the listed rule names exactly (they are case- and separator-sensitive).
  2. Call getActiveRules() (or the rule:// completion endpoint) in your session to enumerate valid rule names and verify the one you reference exists.
  3. If the rule should exist, check that it is defined in a location that is actually loaded/active (correct project directory, rules enabled in settings) before resolving the URL.
  4. If the rule was renamed or deleted, update all prompt/config references to the new rule://<name> URL.

Example fix

// before
await resolveUrl(new URL("rule://code-style"));
// after (verify the exact active rule name first)
const names = getActiveRules().map(r => r.name); // e.g. ["code_style"]
if (names.includes("code_style")) {
  await resolveUrl(new URL("rule://code_style"));
}
Defensive patterns

Strategy: validation

Validate before calling

import { getActiveRules } from "../capability/rule";

function canResolveRule(name: string): boolean {
  return getActiveRules().some(r => r.name === name);
}

const ruleName = url.hostname;
if (!canResolveRule(ruleName)) {
  const available = getActiveRules().map(r => r.name);
  throw new Error(`Rule "${ruleName}" not active. Available: ${available.join(", ") || "none"}`);
}

Type guard

function findActiveRule(name: string): Rule | null {
  return getActiveRules().find(r => r.name === name) ?? null;
}
// use: const rule = findActiveRule(name); if (rule === null) { /* handle */ }

Try / catch

try {
  const resource = await ruleHandler.resolve(url);
  return resource;
} catch (err) {
  if (err instanceof Error && err.message.startsWith("Unknown rule:")) {
    const available = err.message.split("Available:")[1]?.trim() ?? "none";
    return fallbackResource(`Rule not found. Active rules: ${available}`);
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling RuleProtocolHandler.resolve(new URL('rule://some-name')) (or resolving a rule:// internal URL through the URL registry) where 'some-name' does not exactly match the name of any rule returned by getActiveRules(): a typo in the rule name, a rule that was renamed or removed, a rule defined in a directory not loaded as active, or referencing a rule:// URL before rules are registered.

Common situations: Hand-written agent prompts or configs referencing rule:// URLs with stale names after a rules refactor; case or hyphen/underscore mismatches between the URL host and the rule name; rules loaded from a different working directory than the one active at resolve time; relying on a rule that only exists when certain capabilities/directories are enabled.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


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