affaan-m/ECC · error
skill_version is required
Error message
skill_version is required
What it means
Thrown by normalizeExecutionRecord when skill_version (or skillVersion alias) is not a non-empty trimmed string. Checked immediately after skill_id.
Source
Thrown at scripts/lib/skill-evolution/tracker.js:62
function normalizeExecutionRecord(input, options = {}) {
if (!input || typeof input !== 'object' || Array.isArray(input)) {
throw new Error('skill execution payload must be an object');
}
const skillId = input.skill_id || input.skillId;
const skillVersion = input.skill_version || input.skillVersion;
const taskDescription = input.task_description || input.task_attempted || input.taskAttempted;
const outcome = input.outcome;
const recordedAt = input.recorded_at || options.now || new Date().toISOString();
const userFeedback = input.user_feedback || input.userFeedback || null;
if (typeof skillId !== 'string' || skillId.trim().length === 0) {
throw new Error('skill_id is required');
}
if (typeof skillVersion !== 'string' || skillVersion.trim().length === 0) {
throw new Error('skill_version is required');
}
if (typeof taskDescription !== 'string' || taskDescription.trim().length === 0) {
throw new Error('task_description is required');
}
if (!VALID_OUTCOMES.has(outcome)) {
throw new Error('outcome must be one of success, failure, or partial');
}
if (userFeedback !== null && !VALID_FEEDBACK.has(userFeedback)) {
throw new Error('user_feedback must be accepted, corrected, rejected, or null');
}
if (Number.isNaN(Date.parse(recordedAt))) {
throw new Error('recorded_at must be an ISO timestamp');
}
View on GitHub (pinned to 01e15490f0)
Solutions
- Provide skill_version as a non-empty string (skillVersion alias accepted).
- Default to a sentinel like '0.0.0' or 'unversioned' when the skill has no version metadata.
- Read version from the skill frontmatter/versioning module before recording.
Example fix
// before
recordSkillRun({ skill_id: 'foo', task_description: 'x', outcome: 'success' });
// after
recordSkillRun({ skill_id: 'foo', skill_version: skill.version || '0.0.0', task_description: 'x', outcome: 'success' }); Defensive patterns
Strategy: validation
Validate before calling
function resolveVersion(skill) {
const v = skill.version || skill.frontmatter?.version || '0.0.0';
if (typeof v !== 'string' || v.trim().length === 0) throw new TypeError('skill_version missing');
return v;
} Type guard
function hasSkillVersion(input) {
const v = input?.skill_version || input?.skillVersion;
return typeof v === 'string' && v.trim().length > 0;
} Try / catch
try {
recordSkillRun(input);
} catch (err) {
if (/skill_version is required/.test(err.message)) { input.skill_version = '0.0.0'; recordSkillRun(input); }
else throw err;
} Prevention
- Default unversioned skills to a sentinel like '0.0.0'.
- Read version from the skill's versioning metadata when available.
- Validate version presence in the skill authoring lint.
When it happens
Trigger: recordSkillRun({ skill_id, task_description, outcome }) with no skill_version; skill_version: '' ; skill_version omitted because the skill has no version metadata.
Common situations: Skill lacks a version field in its frontmatter; recording logic read the wrong key; version field left blank during authoring.
Related errors
- skill_id is required
- task_description is required
- memory body must contain non-whitespace context.
- target harnesses must contain at least one harness or "all".
- Memory document ${sourcePath} is missing fields: ${missing.j
AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13).
Data as JSON: /api/errors/939cb20618ccaa61.
Report an issue: GitHub.