affaan-m/ECC · error · CapsuleError

capsule.invalid_entry

capsule.invalid_entry

Error message

${errors.join('; ')}

What it means

After building the entry envelope (schema version, run_id, capsule_id, seq, parent hash, payload) and computing its entry hash, append() runs envelope.validateEnvelope() as a final self-check. Any structural violation is thrown as 'capsule.invalid_entry' with all violations joined by ';'. This is an internal consistency gate — it fires when the assembled entry does not satisfy the envelope schema, usually because payload redaction or metadata produced an unexpected shape.

Solutions

  1. Read the ';'-joined violations to identify which envelope fields fail validation.
  2. Verify the capsule meta (run_id, capsule_id, task_family, schema version) is complete and matches the current SCHEMA_VERSION.
  3. Re-create the capsule if it was produced by an incompatible library version; do not patch entries by hand.
  4. Ensure you are not mixing envelope module versions (e.g. a stale patched copy of scripts/lib/eval-harness/envelope.js).

Example fix

// before: appending to a capsule created by an older schema
await capsule.append('fix', 'note', { msg: 'x' }); // capsule.invalid_entry

// after: check compatibility first
const state = readCapsule(capsule.dir);
if (state.ok && state.meta.schema !== envelope.SCHEMA_VERSION) {
  throw new Error(`capsule schema ${state.meta.schema} != library ${envelope.SCHEMA_VERSION}; re-create capsule`);
}
await capsule.append('fix', 'note', { msg: 'x' });
Defensive patterns

Strategy: try-catch

Validate before calling

import { SCHEMA_VERSION } from './envelope.js';
const state = readCapsule(capsule.dir);
if (!state.ok || state.meta.schema !== SCHEMA_VERSION) throw new Error('capsule/library schema mismatch; re-create capsule');

Try / catch

try {
  await capsule.append(lineage, kind, payload);
} catch (e) {
  if (e instanceof CapsuleError && e.code === 'capsule.invalid_entry') {
    throw new Error(`entry failed envelope validation: ${e.message}; check library/capsule version compatibility`);
  }
  throw e;
}

Prevention

When it happens

Trigger: append() called on a capsule whose meta is incomplete (missing run_id/capsule_id) or whose state produced an out-of-spec entry — e.g. empty required fields, wrong seq type, or a redacted payload that ended up violating envelope constraints after the earlier payload checks.

Common situations: A capsule initialized by a different library version with a mismatched SCHEMA_VERSION; corrupted meta.json fields; a custom/patched envelope module partially applied; upgrading the library so old capsules no longer satisfy the new validator.

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


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

Appendix: source

Thrown at scripts/lib/eval-harness/capsule.js:212

        throw new CapsuleError('capsule.payload_denied', `payload keys not allowlisted: ${dropped.join(', ')}`, { dropped });
      }
      const body = {
        schema: envelope.SCHEMA_VERSION,
        run_id: state.meta.run_id,
        capsule_id: state.meta.capsule_id,
        seq: state.entries.length,
        ts: nowIso(this.clock),
        lineage,
        kind,
        effect_class: effectClass,
        harness_version: state.meta.harness_version,
        task_family: state.meta.task_family,
        parent_hash: state.root_hash,
        payload: clean,
      };
      const entry = { ...body, entry_hash: envelope.computeEntryHash(body) };
      const errors = envelope.validateEnvelope(entry);
      if (errors.length > 0) throw new CapsuleError('capsule.invalid_entry', errors.join('; '));
      const bytes = Buffer.from(canonicalJson(entry) + '\n', 'utf8');
      const fd = fs.openSync(this.journalPath, 'a');
      try {
        let offset = 0;
        while (offset < bytes.length) {
          const written = fs.writeSync(fd, bytes, offset, bytes.length - offset, null);
          if (written <= 0) throw new CapsuleError('capsule.write_failed', 'journal write made no progress');
          offset += written;
        }
        fs.fsyncSync(fd);
      } finally {
        fs.closeSync(fd);
      }
      // These fields remain observable for compatibility, but are never used as
      // authoritative append state. A preopened handle always reloads above.
      this.meta = state.meta;
      this.lastHash = entry.entry_hash;
      this.nextSeq = entry.seq + 1;

View on GitHub (pinned to 8321021c54)