affaan-m/ECC · error · Error
skillPath is required
Error message
skillPath is required
What it means
Thrown by normalizeSkillDir in the provenance module (reached via readProvenance, writeProvenance, classifySkillPath, requiresProvenance, getProvenancePath) when skillPath is falsy or not a string. The function accepts either a skill directory or a path ending in SKILL.md (it strips the basename).
Source
Thrown at scripts/lib/skill-evolution/provenance.js:31
IMPORTED: 'imported',
UNKNOWN: 'unknown',
});
function resolveRepoRoot(repoRoot) {
if (repoRoot) {
return path.resolve(repoRoot);
}
return path.resolve(__dirname, '..', '..', '..');
}
function resolveHomeDir(homeDir) {
return homeDir ? path.resolve(homeDir) : os.homedir();
}
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 isWithinRoot(targetPath, rootPath) {
const relativePath = path.relative(rootPath, targetPath);
return relativePath === '' || (
!relativePath.startsWith('..')
&& !path.isAbsolute(relativePath)
);
}
View on GitHub (pinned to 01e15490f0)
Solutions
- Pass the skill directory path as a non-empty string.
- Either the directory or the SKILL.md file path works — basename 'SKILL.md' is auto-stripped.
- Guard the caller: if (!skillPath) return early.
Example fix
// before readProvenance(skill?.path?.dir); // undefined when skill is null // after if (skill?.path?.dir) readProvenance(skill.path.dir);
Defensive patterns
Strategy: type-guard
Validate before calling
if (typeof skillPath !== 'string' || skillPath.trim().length === 0) {
throw new TypeError('skillPath must be a non-empty string');
}
readProvenance(skillPath); Type guard
function isNonEmptyString(v) {
return typeof v === 'string' && v.trim().length > 0;
} Try / catch
try {
readProvenance(skillPath);
} catch (err) {
if (/skillPath is required/.test(err.message)) return null;
throw err;
} Prevention
- Resolve skill directories once at the boundary and pass them down as strings.
- Distinguish the skill record from its path — never pass the record object.
- Add a type check in shared helpers that wrap provenance APIs.
When it happens
Trigger: Calling readProvenance(undefined), readProvenance(null), readProvenance(123), readProvenance(''), or passing a skill object/config instead of its filesystem path.
Common situations: Loop variable undefined (e.g. mapping over an array with a missing entry); destructuring a skill record and passing the whole object instead of record.path; calling provenance APIs before resolving the skill dir.
Related errors
- --config-dir must be an existing absolute directory.
- ${EXECUTABLE_OVERRIDE} must be an absolute path explicitly c
- ${EXECUTABLE_OVERRIDE} does not point to a readable local It
- ${EXECUTABLE_OVERRIDE} must point to the canonical dist/bin/
- Invalid ${name} value: expected a path
AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13).
Data as JSON: /api/errors/325afb87d121d80f.
Report an issue: GitHub.