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

hooks validation failed (${failed} plugin${failed === 1 ? ''

Error message

hooks validation failed (${failed} plugin${failed === 1 ? '' : 's'})

What it means

During `hooks validate`, one or more hook plugin files failed validation (invalid export or a reported reason per file). The command prints each failing plugin with its reason, then throws this aggregate error indicating how many failed.

Source

Thrown at src/cli/hooks.ts:143

  const plugins = await discoverHookPlugins(cwd);
  if (plugins.length === 0) {
    console.log('No plugins found. Run: omx hooks init');
    return;
  }

  let failed = 0;
  for (const plugin of plugins) {
    const result = await validateHookPluginExport(plugin.filePath);
    if (result.valid) {
      console.log(`✓ ${plugin.fileName}`);
    } else {
      failed += 1;
      console.log(`✗ ${plugin.fileName}: ${result.reason || 'invalid export'}`);
    }
  }

  if (failed > 0) {
    throw new Error(`hooks validation failed (${failed} plugin${failed === 1 ? '' : 's'})`);
  }
}

function normalizeDispatchResult(result: unknown): {
  enabled: boolean;
  reason: string;
  results: Record<string, unknown>[];
} {
  if (!result || typeof result !== 'object') {
    return { enabled: false, reason: 'invalid_result', results: [] };
  }

  const obj = result as Record<string, unknown>;
  const results = Array.isArray(obj.results)
    ? obj.results.filter((item): item is Record<string, unknown> => !!item && typeof item === 'object')
    : [];

  return {

View on GitHub (pinned to 3ad79a8a6f)

Solutions

  1. Read the per-plugin `✗ <file>: <reason>` lines printed before the error to identify failures
  2. Fix each plugin's export to match the expected hook plugin shape (see a known-good plugin for reference)
  3. Remove or quarantine broken plugins and re-run `omx hooks validate`
  4. Check the plugin's runtime errors (e.g. syntax errors, missing deps) if reason is 'invalid export'

Example fix

// before (broken plugin)
export const config = { enabled: true };

// after
export default {
  enabled: true,
  dispatch(result) { return result; },
};
Defensive patterns

Strategy: validation

Validate before calling

import { validateHooks } from './src/cli/hooks';
// Dry-run style: wrap validate and inspect per-plugin reasons before it throws
const results = listPluginFiles().map(f => ({ f, ok: checkPluginExports(f) }));
const failing = results.filter(r => !r.ok);
if (failing.length) console.error('Failing plugins:', failing.map(r => r.f));

Type guard

function isValidHookPlugin(mod: unknown): mod is { default: { enabled: boolean; dispatch: (r: unknown) => unknown } } {
  const m = mod as { default?: unknown };
  const d = m?.default;
  return !!d && typeof (d as { enabled?: unknown }).enabled === 'boolean'
    && typeof (d as { dispatch?: unknown }).dispatch === 'function';
}

Try / catch

try {
  await validateHooks();
} catch (e) {
  if (/hooks validation failed/.test((e as Error).message)) {
    // parse per-plugin ✗ lines already printed; fix and re-run
  } else throw e;
}

Prevention

When it happens

Trigger: Running `omx hooks validate` when at least one plugin file in the hooks directory exports something invalid (wrong shape, missing default export, or throwing during load), so `failed > 0`.

Common situations: Editing a hook plugin and breaking its export shape; adding a third-party plugin with an incompatible API; Node version changes breaking a plugin at load time.

Related errors


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