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

  1. Pass the skill directory path as a non-empty string.
  2. Either the directory or the SKILL.md file path works — basename 'SKILL.md' is auto-stripped.
  3. 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

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


AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13). Data as JSON: /api/errors/325afb87d121d80f. Report an issue: GitHub.