can1357/oh-my-pi · error
Managed skill "${name}" SKILL.md is not a regular file; refu
Error message
Managed skill "${name}" SKILL.md is not a regular file; refusing to overwrite it. What it means
When overwriting an existing managed SKILL.md, the stat of the target must be a regular file. assertManagedSkillFileSafeForUpdate throws if it is a directory, FIFO, device, or other non-regular file, refusing to clobber something that isn't a plain file.
Source
Thrown at packages/coding-agent/src/autolearn/managed-skills.ts:131
* follows intermediate components, so a symlinked root would let an otherwise
* valid name write/delete outside the isolated directory (e.g. onto authored
* skills). Checked before composing any child path.
*/
async function assertManagedRootSafe(): Promise<void> {
const rootStat = await fs.lstat(getManagedSkillsDir()).catch(err => {
if (isEnoent(err)) return null;
throw err;
});
if (rootStat?.isSymbolicLink()) {
throw new Error("The managed-skills root is a symlink; refusing to operate outside the managed directory.");
}
}
const UPDATE_FILE_OPEN_FLAGS = fsConstants.O_WRONLY | fsConstants.O_NOFOLLOW;
function assertManagedSkillFileSafeForUpdate(name: string, fileStat: Stats): void {
if (!fileStat.isFile()) {
throw new Error(`Managed skill "${name}" SKILL.md is not a regular file; refusing to overwrite it.`);
}
if (fileStat.nlink > 1) {
throw new Error(
`Managed skill "${name}" SKILL.md has ${fileStat.nlink} hard links; refusing to overwrite a file that may be user-authored elsewhere.`,
);
}
}
async function openManagedSkillFileForUpdate(name: string, file: string) {
try {
return await fs.open(file, UPDATE_FILE_OPEN_FLAGS);
} catch (err) {
if ((err as { code?: string }).code === "ELOOP") {
throw new Error(`Managed skill "${name}" SKILL.md is a symlink; refusing to overwrite it.`);
}
throw err;
}
}View on GitHub (pinned to 9690622007)
Solutions
- Inspect the path with `ls -la ~/.omp/agent/managed-skills/<name>/SKILL.md` to see what it actually is
- Remove or rename the offending non-regular entry, then retry the write
- If it should be a normal skill, recreate it: delete the bad entry and let writeManagedSkill create a fresh SKILL.md
Example fix
// before (shell): SKILL.md is a directory
mv ~/.omp/agent/managed-skills/foo/SKILL.md ~/.omp/agent/managed-skills/foo/SKILL.md.bak-dir
// after (shell): writeManagedSkill then recreates a regular file
writeManagedSkill({ name: "foo", action: "update", ... }) Defensive patterns
Strategy: validation
Validate before calling
import { stat } from "node:fs/promises";
const st = await stat(skillMdPath).catch(() => null);
if (st && !st.isFile()) throw new Error("SKILL.md is not a regular file"); Type guard
function isRegularFile(st: { isFile(): boolean }): boolean {
return st.isFile();
} Try / catch
try {
await writeManagedSkill({ name, action: "update", ... });
} catch (err) {
if (String((err as Error).message).includes("not a regular file")) {
// inspect/remove the bad entry at managed-skills/<name>/SKILL.md, then retry
} else throw err;
} Prevention
- Never replace a managed SKILL.md with a directory, FIFO, or device file
- Inspect managed-skills contents after external tools touch ~/.omp
- Let the managed-skills API create files instead of pre-seeding them manually
When it happens
Trigger: writeManagedSkill (update path) stats an existing <name>/SKILL.md whose stat reports a non-regular file type — e.g. SKILL.md was replaced by a directory or a special file.
Common situations: Someone manually created a SKILL.md directory inside the managed skill folder; a broken tooling sync left a FIFO or socket at that path; a partial filesystem state after a crash.
Related errors
- Managed skill "${name}" SKILL.md has ${fileStat.nlink} hard
- Shared-folder destination escapes its configured root
- Path is not a file: ${pathArg}
- local:// URL must resolve to a file or directory: ${url.href
- File not found: ${filePath}
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/af8f11737b0b49a3.
Report an issue: GitHub.