affaan-m/ECC · error

Missing provenance metadata for ${skillDir}

Error message

Missing provenance metadata for ${skillDir}

What it means

Thrown by readProvenance when the .provenance.json file does not exist AND provenance is required. Provenance is required when options.required === true OR requiresProvenance() classifies the skill dir as learned/imported (i.e. under ~/.claude/skills/learned or /imported). For curated/unknown paths with no file, readProvenance returns null instead.

Source

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

    errors,
  };
}

function assertValidProvenance(record) {
  const validation = validateProvenance(record);
  if (!validation.valid) {
    throw new Error(`Invalid provenance metadata: ${validation.errors.join('; ')}`);
  }
}

function readProvenance(skillPath, options = {}) {
  const skillDir = normalizeSkillDir(skillPath);
  const provenancePath = getProvenancePath(skillDir);
  const provenanceRequired = options.required === true || requiresProvenance(skillDir, options);

  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);

View on GitHub (pinned to 01e15490f0)

Solutions

  1. Create the metadata first with writeProvenance(dir, validRecord).
  2. If absence is acceptable, call readProvenance without options.required and handle a null return.
  3. Move the skill into a curated root (repo skills/) where provenance is optional, or fix repoRoot/homeDir so the path classifies correctly.

Example fix

// before
const p = readProvenance(learnedDir); // throws if no .provenance.json

// after
const p = readProvenance(learnedDir);
// or, if you just want a best-effort read:
const p = readProvenance(learnedDir, { required: false }); // null when absent
// or create it:
writeProvenance(learnedDir, { source, created_at, confidence, author });
Defensive patterns

Strategy: try-catch

Validate before calling

const { requiresProvenance } = require('./provenance');
function safeReadProvenance(dir, options = {}) {
  if (!fs.existsSync(getProvenancePath(dir))) {
    if (!options.required && !requiresProvenance(dir, options)) return null;
  }
  return readProvenance(dir, options);
}

Type guard

function provenanceExists(skillPath) {
  return fs.existsSync(path.join(skillPath, '.provenance.json'));
}

Try / catch

try {
  return readProvenance(dir);
} catch (err) {
  if (/Missing provenance metadata/.test(err.message)) {
    writeProvenance(dir, buildDefaultRecord());
    return readProvenance(dir);
  }
  throw err;
}

Prevention

When it happens

Trigger: readProvenance('/home/u/.claude/skills/learned/foo') where foo has no .provenance.json; readProvenance(anyDir, { required: true }) with no file present.

Common situations: A learned/imported skill was created without provenance metadata; the skill directory was moved/copied without the .provenance.json; fresh import pipeline skipped the metadata step; options.required forced on a path that legitimately lacks it.

Related errors


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