affaan-m/ECC · error · Error

Invalid provenance metadata: ${validation.errors.join('; ')}

Error message

Invalid provenance metadata: ${validation.errors.join('; ')}

What it means

Thrown by assertValidProvenance, which runs validateProvenance and joins all accumulated errors. A valid provenance record must be an object with: `source` (non-empty string), `created_at` (parseable ISO timestamp), `confidence` (finite number in 0..1), and `author` (non-empty string). Reached on both writeProvenance and readProvenance of an existing file.

Source

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

    errors.push('confidence must be a number');
  } else if (record.confidence < 0 || record.confidence > 1) {
    errors.push('confidence must be between 0 and 1');
  }

  if (typeof record.author !== 'string' || record.author.trim().length === 0) {
    errors.push('author is required');
  }

  return {
    valid: errors.length === 0,
    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);

View on GitHub (pinned to 01e15490f0)

Solutions

  1. Ensure all four fields: source (string), created_at (ISO string), confidence (number 0..1), author (string).
  2. Pre-check with validateProvenance(record) — it returns { valid, errors } without throwing.
  3. Regenerate the file via writeProvenance with a fully-formed record, or delete it and re-import the skill.

Example fix

// before
writeProvenance(dir, {
  source: 'import:github',
  created_at: '2025-01-01',
  confidence: '0.9',  // string, not number
  author: ''
});

// after
writeProvenance(dir, {
  source: 'import:github',
  created_at: new Date().toISOString(),
  confidence: 0.9,
  author: 'alice'
});
Defensive patterns

Strategy: validation

Validate before calling

const { validateProvenance } = require('./provenance');
const result = validateProvenance(record);
if (!result.valid) {
  throw new Error('fix provenance: ' + result.errors.join(', '));
}
writeProvenance(dir, record);

Type guard

function isProvenanceRecord(r) {
  return r && typeof r === 'object' && !Array.isArray(r)
    && typeof r.source === 'string' && r.source.trim().length > 0
    && typeof r.author === 'string' && r.author.trim().length > 0
    && typeof r.confidence === 'number' && r.confidence >= 0 && r.confidence <= 1
    && !Number.isNaN(Date.parse(r.created_at));
}

Try / catch

try {
  writeProvenance(dir, record);
} catch (err) {
  if (/Invalid provenance metadata/.test(err.message)) {
    const v = validateProvenance(record); console.warn(v.errors);
  } else throw err;
}

Prevention

When it happens

Trigger: writeProvenance(dir, { source: 'x', created_at: 'x', confidence: 'high', author: '' }) (multiple errors joined by '; '); readProvenance of a hand-edited .provenance.json missing author or with confidence as a string; a record missing entirely.

Common situations: Hand-editing .provenance.json and dropping a field; old schema lacking `author`; confidence stored as a stringified number; corrupted JSON after a merge conflict.

Related errors


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