can1357/oh-my-pi · error

Managed skill "${name}" does not exist. Use action "create"

Error message

Managed skill "${name}" does not exist. Use action "create" to add it.

What it means

writeManagedSkill with action "update" requires the managed SKILL.md to already exist; lstat returning null (ENOENT) produces this error. It prevents update from silently creating files, keeping create/update semantics strict and symmetric with error 700.

Source

Thrown at packages/coding-agent/src/autolearn/managed-skills.ts:213

				await fs.writeFile(file, content, { flag: "wx" });
			} catch (err) {
				if ((err as { code?: string }).code === "EEXIST") {
					throw new Error(`Managed skill "${name}" already exists. Use action "update" to change it.`);
				}
				throw err;
			}
			return { path: file };
		}
		// update: the file must already exist, be a plain managed file, and must
		// not share an inode with a user-authored file via hard link. Open the
		// checked file handle before truncating so a path swap after lstat cannot
		// redirect the write into a symlink or newly hard-linked target.
		const fileStat = await fs.lstat(file).catch(err => {
			if (isEnoent(err)) return null;
			throw err;
		});
		if (fileStat === null) {
			throw new Error(`Managed skill "${name}" does not exist. Use action "create" to add it.`);
		}
		if (fileStat.isSymbolicLink()) {
			throw new Error(`Managed skill "${name}" SKILL.md is a symlink; refusing to overwrite it.`);
		}
		assertManagedSkillFileSafeForUpdate(name, fileStat);
		const handle = await openManagedSkillFileForUpdate(name, file);
		try {
			const openStat = await handle.stat();
			assertManagedSkillFileSafeForUpdate(name, openStat);
			await handle.truncate(0);
			await handle.writeFile(content);
		} finally {
			await handle.close();
		}
		return { path: file };
	});
}

View on GitHub (pinned to 9690622007)

Solutions

  1. Call writeManagedSkill with action "create" to add the missing skill.
  2. Verify the exact skill name (lowercase letters/digits/hyphens) matches the directory on disk.
  3. Check that the managed-skills directory is the one being inspected (~/.omp/agent/managed-skills, not the authored skills dir).

Example fix

// before
await writeManagedSkill({ action: "update", name: "my-skill", description: "d", body: "b" });
// after
const file = `${getManagedSkillsDir()}/my-skill/SKILL.md`;
const exists = await Bun.file(file).exists();
await writeManagedSkill({ action: exists ? "update" : "create", name: "my-skill", description: "d", body: "b" });
Defensive patterns

Strategy: validation

Validate before calling

const file = `${getManagedSkillsDir()}/${sanitizeSkillName(name)}/SKILL.md`;
const exists = await fs.lstat(file).then(() => true).catch(e => { if (isEnoent(e)) return false; throw e; });
if (!exists) throw new Error(`refusing to update missing skill ${name}`);

Try / catch

try {
  await writeManagedSkill({ action: "update", name, description, body });
} catch (err) {
  if (err instanceof Error && err.message.includes('does not exist')) {
    await writeManagedSkill({ action: "create", name, description, body });
  } else throw err;
}

Prevention

When it happens

Trigger: Calling writeManagedSkill({ action: "update", name, ... }) when ~/.omp/agent/managed-skills/<name>/SKILL.md does not exist — the skill was deleted, never created, or the name is misspelled.

Common situations: An agent tries to enhance a skill that was pruned between sessions; a typo in the skill name; code assumed a prior create succeeded but it failed.

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/83612eff4fcf0dc0. Report an issue: GitHub.