affaan-m/ECC · error · Error
skillPath is required
Error message
skillPath is required
What it means
normalizeSkillDir in scripts/lib/skill-evolution/versioning.js throws 'skillPath is required' when the skillPath argument is falsy or not a string. It is the entry validation for path resolution helpers (getSkillFilePath, getVersionsDir, getEvolutionDir), which cannot compute any paths without a base skill directory. It also accepts a direct path to a SKILL.md file and resolves it to its parent directory.
Solutions
- Pass the skill directory path (or the SKILL.md file path) as a non-empty string to the helper.
- If the path is discovered dynamically, resolve the skill directory first and fail early with a clear message when discovery returns nothing.
- For CLI callers, validate that the --skill-path option is present and non-empty before invoking the versioning helpers.
Example fix
// before
const versionsDir = versioning.getVersionsDir(opts.skillPath); // opts.skillPath may be undefined
// after
const skillPath = opts.skillPath ?? path.join(process.cwd(), 'skills', opts.skillName);
if (!skillPath || typeof skillPath !== 'string') {
throw new Error('--skill-path or --skill-name is required');
}
const versionsDir = versioning.getVersionsDir(skillPath); Defensive patterns
Strategy: type-guard
Validate before calling
function assertSkillPath(skillPath) {
if (!skillPath || typeof skillPath !== 'string') {
throw new Error('skillPath is required: pass the skill directory or its SKILL.md path');
}
} Type guard
function hasSkillPath(v) {
return typeof v === 'string' && v.length > 0;
} Try / catch
try {
const versionsDir = versioning.getVersionsDir(skillPath);
} catch (err) {
if (err.message === 'skillPath is required') {
console.error('No skill path provided; resolve the skill directory (or pass its SKILL.md path) first.');
process.exitCode = 1;
return;
}
throw err;
} Prevention
- Resolve the skill directory once at startup and assert it before calling any versioning helper.
- Never forward possibly-null results of skill discovery directly into getSkillFilePath/getVersionsDir/getEvolutionDir.
- In CLI scripts, validate that --skill-path (or an equivalent) is present before running path computations.
When it happens
Trigger: Calling getSkillFilePath/getVersionsDir/getEvolutionDir with skillPath undefined, null, an empty string, or a non-string (number, object). Also occurs when an upstream lookup for the skill directory returned nothing and the null result was forwarded.
Common situations: Calling the helpers before a skill is installed/located on disk; a failed skill-name-to-path resolution earlier in the pipeline returning null; CLI scripts where the --skill-path flag was not provided; refactors that changed the helper signature and dropped the argument.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- must be a number
- outcome must be one of success, failure, or partial
- recorded_at must be an ISO timestamp
- skill execution payload must be an object
- skill_id is required
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/ab988770e7b61d99.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/lib/skill-evolution/versioning.js:18
'use strict';
const fs = require('fs');
const path = require('path');
const { appendFile, ensureDir } = require('../utils');
const VERSION_DIRECTORY_NAME = '.versions';
const EVOLUTION_DIRECTORY_NAME = '.evolution';
const EVOLUTION_LOG_TYPES = Object.freeze([
'observations',
'inspections',
'amendments',
]);
function normalizeSkillDir(skillPath) {
if (!skillPath || typeof skillPath !== 'string') {
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}`);View on GitHub (pinned to 8321021c54)