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

  1. Pass the skill directory path (or the SKILL.md file path) as a non-empty string to the helper.
  2. If the path is discovered dynamically, resolve the skill directory first and fail early with a clear message when discovery returns nothing.
  3. 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

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


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)