can1357/oh-my-pi · error
Managed skill "${safe}" does not exist.
Error message
Managed skill "${safe}" does not exist. What it means
deleteManagedSkill maps an ENOENT from fs.rm (the skill directory vanished or never existed) into this explicit error rather than treating delete as a silent no-op. Deletion of a managed skill is expected to target an existing skill.
Source
Thrown at packages/coding-agent/src/autolearn/managed-skills.ts:250
/** Delete a managed skill directory. Throws when it does not exist. */
export async function deleteManagedSkill(name: string): Promise<void> {
const safe = sanitizeSkillName(name);
await serializeSkillMutation(safe, async () => {
await assertManagedRootSafe();
const dir = path.join(getManagedSkillsDir(), safe);
// Refuse to follow a symlinked skill directory (rm would delete the target).
const dirStat = await fs.lstat(dir).catch(err => {
if (isEnoent(err)) return null;
throw err;
});
if (dirStat?.isSymbolicLink()) {
throw new Error(`Managed skill "${safe}" is a symlink; refusing to delete outside the managed directory.`);
}
try {
await fs.rm(dir, { recursive: true });
} catch (err) {
if (isEnoent(err)) {
throw new Error(`Managed skill "${safe}" does not exist.`);
}
throw err;
}
});
}
View on GitHub (pinned to 9690622007)
Solutions
- Verify the skill exists before deleting (lstat the directory) and skip the delete if absent.
- Check the skill name spelling against the managed-skills directory listing.
- Treat this error as "already gone" and swallow it if your workflow is idempotent cleanup.
Example fix
// before
await deleteManagedSkill("my-skill");
// after
const dir = `${getManagedSkillsDir()}/my-skill`;
if (await Bun.file(dir).exists()) await deleteManagedSkill("my-skill"); Defensive patterns
Strategy: validation
Validate before calling
const dir = `${getManagedSkillsDir()}/${sanitizeSkillName(name)}`;
const exists = await fs.lstat(dir).then(() => true).catch(e => { if (isEnoent(e)) return false; throw e; });
if (!exists) return; // already gone; idempotent delete Try / catch
try {
await deleteManagedSkill(name);
} catch (err) {
if (!(err instanceof Error && err.message.includes('does not exist'))) throw err;
// treat as already deleted
} Prevention
- Make delete paths idempotent: existence check first, or swallow the not-exist error.
- Verify names against a fresh directory listing rather than stale in-memory lists.
- Serialize cross-process deletes if multiple omp instances may prune concurrently.
When it happens
Trigger: deleteManagedSkill(name) when ~/.omp/agent/managed-skills/<name>/ does not exist — already deleted, never created, or name misspelled.
Common situations: Double-delete in a retry path; an agent cleaning up skills concurrently (same-name mutations are serialized in-process but not cross-process); typo in the skill name.
Understand the failure class
Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.
Related errors
- Managed skill "${name}" does not exist. Use action "create"
- unknown filetype: {ft_debug}
- Is a directory
- Too many levels of symbolic links
- {}: {error}
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/58fed49463162949.
Report an issue: GitHub.