can1357/oh-my-pi · error · Error
Unknown capability: "${capabilityId}". Define it first with
Error message
Unknown capability: "${capabilityId}". Define it first with defineCapability(). What it means
registerProvider() looks up the capability by id in the registry and throws if no capability was previously created via defineCapability(). Providers can only attach to capabilities that exist; this ordering is enforced at registration time.
Source
Thrown at packages/coding-agent/src/capability/index.ts:67
/**
* Define a new capability.
*/
export function defineCapability<T>(def: Omit<Capability<T>, "providers">): Capability<T> {
if (capabilities.has(def.id)) {
throw new Error(`Capability "${def.id}" is already defined`);
}
const capability: Capability<T> = { ...def, providers: [] };
capabilities.set(def.id, capability as Capability<unknown>);
return capability;
}
/**
* Register a provider for a capability.
*/
export function registerProvider<T>(capabilityId: string, provider: Provider<T>): void {
const capability = capabilities.get(capabilityId);
if (!capability) {
throw new Error(`Unknown capability: "${capabilityId}". Define it first with defineCapability().`);
}
// Store provider metadata (for cross-capability display)
if (!providerMeta.has(provider.id)) {
providerMeta.set(provider.id, {
displayName: provider.displayName,
description: provider.description,
});
}
// Track which capabilities this provider is registered for
if (!providerCapabilities.has(provider.id)) {
providerCapabilities.set(provider.id, new Set());
}
providerCapabilities.get(provider.id)!.add(capabilityId);
// Insert in priority order (highest first)
const providers = capability.providers as Provider<T>[];View on GitHub (pinned to 9690622007)
Solutions
- Import and call defineCapability for the id before registerProvider — usually by importing the capability object and passing its .id
- Verify the id string matches the defined capability exactly (typos, renames)
- Fix import order so the capability module's side effects run first
- Better: pass the typed capability object instead of a raw string so the id comes from the definition
Example fix
// before
registerProvider("hook", myProvider);
// after
import { hookCapability } from "./capabilities";
registerProvider(hookCapability.id, myProvider); Defensive patterns
Strategy: validation
Validate before calling
import { capabilities } from "@oh-my-pi/pi-coding-agent/capability";
if (!capabilities.has(hookCapability.id)) {
throw new Error("capability module not loaded; import it before registering providers");
}
registerProvider(hookCapability.id, provider); Try / catch
try {
registerProvider(capabilityId, provider);
} catch (err) {
if (err instanceof Error && err.message.startsWith('Unknown capability')) {
console.error(`capability "${capabilityId}" undefined — check defineCapability order/ids`);
} else throw err;
} Prevention
- Pass the capability object's .id, not a hand-written string
- Import the capability definition module before provider registration
- Keep define/register pairs in the same module or an explicit init order
- Grep for the id literal when renaming capabilities
When it happens
Trigger: Calling registerProvider("someId", provider) before (or without ever) calling defineCapability({ id: "someId" }) — e.g. wrong capability id string, typo, or module load order where the provider module is imported before the capability module.
Common situations: A typo in the capability id string; import hoisting/order issues where provider registration runs before the capability definition module; renaming a capability but not updating provider registration call sites.
Related errors
- Capability "${def.id}" is already defined
- Destination option ${key} must be a string
- Unknown capability: "${capabilityId}"
- Unknown auth-broker action: ${String(_exhaustive)}
- Unknown auth-gateway action: ${String(_exhaustive)}
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/c7469ab26b520f40.
Report an issue: GitHub.