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

  1. Verify the skill exists before deleting (lstat the directory) and skip the delete if absent.
  2. Check the skill name spelling against the managed-skills directory listing.
  3. 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

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


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