affaan-m/ECC · error · Error
Skill file not found
Error message
Skill file not found: ${skillFilePath} What it means
ensureSkillExists resolves the SKILL.md path for a given skill directory and throws when that file does not exist on disk. The library requires every skill it versions or rolls back to have a real SKILL.md at the normalized skill directory. The message includes the resolved absolute path so you can see exactly where it looked.
Solutions
- Verify the resolved path in the error message and create the missing SKILL.md at that exact location
- Fix the skillPath argument so it points at the directory containing SKILL.md (not the file itself)
- Check casing/extension of the file — it must be exactly SKILL.md
- Re-clone or restore the skill directory if it was deleted or moved
Example fix
// before
await rollbackTo('./skills/MySkill', 2); // wrong casing / wrong path
// after
await rollbackTo('./skills/my-skill', 2); // dir containing SKILL.md exists Defensive patterns
Strategy: type-guard
Validate before calling
const fs = require('fs');
if (!fs.existsSync(require('path').join(skillPath, 'SKILL.md'))) {
throw new Error(`Aborting: no SKILL.md in ${skillPath}`);
} Type guard
function hasSkillFile(dir) {
return typeof dir === 'string' && fs.existsSync(path.join(dir, 'SKILL.md'));
} Try / catch
try {
ensureSkillExists(skillPath);
} catch (err) {
if (err.message.startsWith('Skill file not found')) {
console.error(`Check skillPath '${skillPath}': ${err.message}`);
process.exitCode = 1;
} else throw err;
} Prevention
- Always pass the skill directory, never the SKILL.md file path
- Keep SKILL.md naming exact — uppercase, .md extension
- Resolve relative paths against the repo root before calling
- List skills programmatically (readdir) rather than hardcoding paths
When it happens
Trigger: Calling ensureSkillExists (directly or via ensureSkillVersioning or rollbackTo) with a skillPath whose directory exists but contains no SKILL.md, or whose path resolves to the wrong directory after normalization.
Common situations: Typo in the skill directory name; skill folder created manually with only a draft file (e.g. skill.md lowercase); passing a path to the file itself instead of the directory so normalization doubles up SKILL.md; running the tool from a different repo root so relative skill paths miss; skill deleted or renamed before a rollback.
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
- all overlays must be readable local files
- all takes must be readable local files
- artifact path must stay beneath output root
- base video must be a readable local file
- FileNotFoundError(source)
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/37f44a1de8f06bb2.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/lib/skill-evolution/versioning.js:36
throw new Error('skillPath is required');
}
const resolvedPath = path.resolve(skillPath);
if (path.basename(resolvedPath) === 'SKILL.md') {
return path.dirname(resolvedPath);
}
return resolvedPath;
}
function getSkillFilePath(skillPath) {
return path.join(normalizeSkillDir(skillPath), 'SKILL.md');
}
function ensureSkillExists(skillPath) {
const skillFilePath = getSkillFilePath(skillPath);
if (!fs.existsSync(skillFilePath)) {
throw new Error(`Skill file not found: ${skillFilePath}`);
}
return skillFilePath;
}
function getVersionsDir(skillPath) {
return path.join(normalizeSkillDir(skillPath), VERSION_DIRECTORY_NAME);
}
function getEvolutionDir(skillPath) {
return path.join(normalizeSkillDir(skillPath), EVOLUTION_DIRECTORY_NAME);
}
function getEvolutionLogPath(skillPath, logType) {
if (!EVOLUTION_LOG_TYPES.includes(logType)) {
throw new Error(`Unknown evolution log type: ${logType}`);
}
View on GitHub (pinned to 8321021c54)