affaan-m/ECC · error · CapsuleError
failure.reason
Error message
failure.reason
What it means
During Capsule.create, the newly built metadata object is validated via metadataFailure(meta); if validation fails, the returned failure's code and reason (message 'failure.reason' — the actual text comes from metadataFailure) are rethrown as a CapsuleError before any directory or files are written. This guards invariants such as invalid identifiers, missing schema/harness/task_family values, or malformed timestamps in the options you supplied.
Solutions
- Read the failure.code / error message to see which metadata field failed validation
- Validate your run_id/capsule_id (identifier format), harness_version, task_family, and clock output before calling create
- Omit options entirely to use the library's generated defaults (newId('run'), newId('capsule'), 'unknown', 'unspecified')
- Wrap create in try-catch on the returned CapsuleError code and fix the offending option
Example fix
// before
Capsule.create(dir, { capsule_id: userInput });
// after
const capsuleId = /^[A-Za-z0-9_-]+$/.test(userInput ?? '') ? userInput : undefined;
const capsule = Capsule.create(dir, capsuleId ? { capsule_id: capsuleId } : {}); Defensive patterns
Strategy: validation
Validate before calling
function validateCapsuleOptions(o = {}) {
const idRe = /^[A-Za-z0-9._-]+$/;
for (const k of ['run_id', 'capsule_id', 'harness_version', 'task_family']) {
if (o[k] !== undefined && (typeof o[k] !== 'string' || o[k] === '')) {
throw new Error(`${k} must be a non-empty string`);
}
if (o[k] !== undefined && !idRe.test(o[k])) {
throw new Error(`${k} contains invalid characters`);
}
}
} Type guard
function isStringOption(v) {
return v === undefined || (typeof v === 'string' && v.length > 0);
} Try / catch
try {
const capsule = Capsule.create(dir, options);
} catch (e) {
if (e.code && e.code.startsWith('capsule.')) {
console.error('capsule metadata rejected:', e.code, e.message);
} else throw e;
} Prevention
- Omit optional metadata options to let the library generate valid defaults
- Never pass null where the API expects the option to be absent — use undefined
- Constrain custom IDs to a safe charset and validate user input before injecting it
- If using a custom clock, verify its timestamp format matches the library's ISO expectations
When it happens
Trigger: Passing Capsule.create(dir, { run_id, capsule_id, harness_version, task_family }) with values that violate metadata rules (e.g. empty, wrong format/charset, or of the wrong type such as non-string); a clock option producing an invalid timestamp; supplying null instead of omitting an option.
Common situations: Generating IDs with a custom scheme containing illegal characters; wiring user input straight into capsule_id/run_id; a custom clock whose nowIso output is malformed; refactors that pass undefined-checked but null-valued options.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- artifact lacks genre binding
- Choose at least one guided harness: Claude, Codex, or Kimi.
- genre has no references
- Invalid : unsupported hook event
- invalid plan-canvas server port
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/13075be8eb59a1bb.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/lib/eval-harness/capsule.js:152
this.lastHash = envelope.GENESIS_HASH;
this.nextSeq = 0;
}
static create(dir, options = {}) {
const resolved = path.resolve(dir);
if (fs.existsSync(path.join(resolved, META_FILE))) {
throw new CapsuleError('capsule.exists', `capsule already exists at ${resolved}`);
}
const meta = {
schema: envelope.SCHEMA_VERSION,
run_id: options.run_id === undefined ? newId('run') : options.run_id,
capsule_id: options.capsule_id === undefined ? newId('capsule') : options.capsule_id,
harness_version: options.harness_version === undefined ? 'unknown' : options.harness_version,
task_family: options.task_family === undefined ? 'unspecified' : options.task_family,
created_at: nowIso(options.clock),
};
const failure = metadataFailure(meta);
if (failure) throw new CapsuleError(failure.code, failure.reason);
fs.mkdirSync(resolved, { recursive: true });
fs.writeFileSync(path.join(resolved, META_FILE), canonicalJson(meta) + '\n', 'utf8');
fs.writeFileSync(path.join(resolved, JOURNAL_FILE), '', 'utf8');
return new Capsule(resolved, meta, options);
}
static open(dir, options = {}) {
const resolved = path.resolve(dir);
const state = readCapsule(resolved);
if (!state.ok) {
throw new CapsuleError(state.code, state.reason, { failed_at: state.failed_at });
}
const capsule = new Capsule(resolved, state.meta, options);
if (state.entries.length > 0) {
const last = state.entries[state.entries.length - 1];
capsule.lastHash = last.entry_hash;
capsule.nextSeq = last.seq + 1;
}View on GitHub (pinned to 8321021c54)