Yeachan-Heo/oh-my-codex · error · Error
plugin_skill_mirror_out_of_sync\nkind=${mismatch.kind}\n${mi
Error message
plugin_skill_mirror_out_of_sync\nkind=${mismatch.kind}\n${mismatch.skillName ? `skill=${mismatch.skillName}` : undefined}\nmessage=${mismatch.message}\n${mismatch.expected ? `expected=${JSON.stringify(mismatch.expected)}` : undefined}\n${mismatch.actual ? `actual=${JSON.stringify(mismatch.actual)}` : undefined} What it means
Thrown by assertSkillMirror when the on-disk mirror of plugin skills does not match the expected catalog state (missing/extra/changed skill files or metadata). The message embeds machine-readable key=value lines (kind, skill, expected, actual) describing the exact mismatch. It is an internal consistency assertion raised during syncPluginMirror, meaning the mirror directory diverged from the source of truth.
Source
Thrown at src/catalog/skill-mirror.ts:147
return null;
}
export async function assertSkillMirror(
expectedSkillsDir: string,
actualSkillsDir: string,
expectedSkillNames: readonly string[],
options: DirectoryMirrorOptions = {},
): Promise<void> {
const mismatch = await compareSkillMirror(
expectedSkillsDir,
actualSkillsDir,
expectedSkillNames,
options,
);
if (!mismatch) return;
throw new Error(
[
'plugin_skill_mirror_out_of_sync',
`kind=${mismatch.kind}`,
mismatch.skillName ? `skill=${mismatch.skillName}` : undefined,
`message=${mismatch.message}`,
mismatch.expected ? `expected=${JSON.stringify(mismatch.expected)}` : undefined,
mismatch.actual ? `actual=${JSON.stringify(mismatch.actual)}` : undefined,
].filter(Boolean).join('\n'),
);
}
View on GitHub (pinned to 3ad79a8a6f)
Solutions
- Inspect the kind/skill/expected/actual fields in the message to identify which mirrored skill diverged
- Delete or restore the affected mirrored skill directory and re-run the plugin mirror sync
- Reinstall or re-register the plugin that owns the mismatched skill
- If the mirror is stale from an upgrade, regenerate the whole mirror rather than patching individual files
Example fix
# before rm -rf .omx/skills/my-skill # partial manual delete -> out of sync # after omx plugin sync-mirror # re-run full sync to rebuild mirror
Defensive patterns
Strategy: validation
Validate before calling
// Before sync, verify each expected skill file exists and matches expected names
import { readdirSync, existsSync } from 'node:fs';
const expected = new Set(expectedSkillNames); // from plugin manifest
const actual = new Set(readdirSync(actualSkillsDir).filter(f => f.endsWith('.md')));
for (const name of expected) if (!actual.has(name)) throw new Error(`missing mirror skill: ${name}`);
for (const name of actual) if (!expected.has(name)) console.warn(`extra mirror skill: ${name}`); Try / catch
try {
await syncPluginMirror(plugin);
} catch (e) {
if (e instanceof Error && e.message.includes('plugin_skill_mirror_out_of_sync')) {
await rm(actualSkillsDir, { recursive: true, force: true });
await syncPluginMirror(plugin); // rebuild from scratch
} else throw e;
} Prevention
- Never hand-edit mirrored skill files; edit the source plugin and re-sync
- Run mirror sync immediately after adding/removing plugins
- Keep the mirror directory out of manual git merges or regenerate it in CI
When it happens
Trigger: Calling the skill-mirror sync flow when the mirrored skills directory has been manually edited, partially deleted, written by an older plugin version, or when a plugin was added/removed without re-running the mirror sync.
Common situations: Developers hand-edit mirrored skill files, stale mirrors left behind after upgrading a plugin, interrupted sync leaving partial files, or checkout of a repo where the mirror directory is gitignored.
Related errors
- autoresearch_candidate_missing:${candidateFile}
- Refusing cancellation through non-regular run state target:
- Refusing cancellation through non-regular state target ${ref
- Refusing cancellation outside authorized state root: ${ref.p
- No mission summary found at ${summaryPath}.
AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27).
Data as JSON: /api/errors/7b25787df16c4e11.
Report an issue: GitHub.