affaan-m/ECC · error · Error

Provenance metadata is only required for learned or…

Error message

Provenance metadata is only required for learned or imported skills: ${skillDir}

What it means

writeProvenance() in the skill-evolution library persists a provenance metadata record next to a skill directory. Before writing, it checks requiresProvenance(); if the skill is not classified as learned or imported (e.g. it is a built-in/manual skill), provenance is considered meaningless and the function refuses with this error. This is an unsupported-operation guard: provenance tracking only applies to skills whose origin came from learning or import.

Solutions

  1. Only call writeProvenance for skills classified as learned or imported; check requiresProvenance(skillDir, options) first.
  2. Pass options that correctly mark the skill as learned/imported if it genuinely is one (e.g. the origin/type option the function reads).
  3. Fix the skill's metadata (type/origin fields) if it was misclassified as a non-learned skill.
  4. Skip provenance writing for built-in/manual skills in your automation script instead of forcing it.

Example fix

// before
await writeProvenance('/skills/built-in/linting', record);

// after
if (requiresProvenance(normalizeSkillDir('/skills/built-in/linting'), { origin: 'learned' })) {
  await writeProvenance('/skills/built-in/linting', record, { origin: 'learned' });
}
Defensive patterns

Strategy: validation

Validate before calling

import { requiresProvenance, normalizeSkillDir } from './scripts/lib/skill-evolution/provenance.js';

function canWriteProvenance(skillPath, options = {}) {
  const skillDir = normalizeSkillDir(skillPath);
  return requiresProvenance(skillDir, options);
}

if (!canWriteProvenance(skillPath, options)) {
  throw new Error(`skip provenance write: ${skillPath} is not a learned/imported skill`);
}

Type guard

function isProvenanceEligible(skill) {
  return skill != null && (skill.type === 'learned' || skill.type === 'imported');
}

Try / catch

try {
  await writeProvenance(skillPath, record, options);
} catch (err) {
  if (err.message.startsWith('Provenance metadata is only required')) {
    console.warn(`Skipping provenance for non-learned skill: ${skillPath}`);
    return; // treat as no-op for built-in/manual skills
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling writeProvenance(skillPath, record) where the resolved skillDir maps to a skill whose type/origin (per requiresProvenance) is not 'learned' or 'imported' — e.g. a stock/bundled skill — and no options override that classification.

Common situations: Automating skill bookkeeping across a whole skills/ directory and accidentally running provenance writes for built-in skills; calling the API after refactoring skill metadata so the type field no longer reads 'learned'/'imported'; copy-pasting a provenance-writing script from an import workflow onto a manually authored skill.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16). Data as JSON: /api/errors/eb01edc734d40f23. Report an issue: GitHub.

Appendix: source

Thrown at scripts/lib/skill-evolution/provenance.js:162

  if (!fs.existsSync(provenancePath)) {
    if (provenanceRequired) {
      throw new Error(`Missing provenance metadata for ${skillDir}`);
    }

    return null;
  }

  const record = JSON.parse(fs.readFileSync(provenancePath, 'utf8'));
  assertValidProvenance(record);
  return record;
}

function writeProvenance(skillPath, record, options = {}) {
  const skillDir = normalizeSkillDir(skillPath);

  if (!requiresProvenance(skillDir, options)) {
    throw new Error(`Provenance metadata is only required for learned or imported skills: ${skillDir}`);
  }

  assertValidProvenance(record);

  const provenancePath = getProvenancePath(skillDir);
  ensureDir(skillDir);
  fs.writeFileSync(provenancePath, `${JSON.stringify(record, null, 2)}\n`, 'utf8');

  return {
    path: provenancePath,
    record: { ...record },
  };
}

module.exports = {
  PROVENANCE_FILE_NAME,
  SKILL_TYPES,
  classifySkillPath,

View on GitHub (pinned to 8321021c54)