affaan-m/ECC · error · CapsuleError

capsule.payload_invalid

capsule.payload_invalid

Error message

payloadErrors.join('; ')

What it means

append() runs every payload through envelope.redactPayload(), which both validates payload values and scans them for secrets. Validation errors (e.g. non-scalar values, oversized strings, disallowed shapes) are returned in the errors array and thrown joined with ';' under code 'capsule.payload_invalid'. The message lists every failed constraint so the caller can fix all of them in one pass.

Solutions

  1. Read the joined message — each ';'-separated segment names one failing key and reason; fix them all.
  2. Reduce the payload to small scalar fields (strings/numbers/booleans) relevant to the event.
  3. Confirm the argument order is append(lineage, kind, payload, options) and nothing was swapped.
  4. Pre-validate the payload with the same redactPayload helper (or a local schema check) before calling append().

Example fix

// before: passing a complex object
await capsule.append('fix', 'note', { error: new Error('boom'), stack: err.stack }); // capsule.payload_invalid

// after: flat scalar payload
await capsule.append('fix', 'note', { message: 'boom', phase: 'green' });
Defensive patterns

Strategy: validation

Validate before calling

const clean = envelope.redactPayload(payload, {});
if (clean.errors.length > 0) throw new Error(`invalid payload: ${clean.errors.join('; ')}`);

Type guard

function isScalarPayload(payload) {
  return payload != null && typeof payload === 'object' &&
    Object.values(payload).every(v => ['string', 'number', 'boolean'].includes(typeof v));
}

Try / catch

try {
  await capsule.append(lineage, kind, payload);
} catch (e) {
  if (e instanceof CapsuleError && e.code === 'capsule.payload_invalid') {
    console.error('Fix each payload constraint:', e.message.split('; '));
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling append(lineage, kind, payload) with a payload containing values that fail redactPayload validation — e.g. nested objects/functions where scalars are expected, values exceeding size limits, or fields with invalid types.

Common situations: Passing a whole error object or class instance as payload; accidentally passing options as the payload (swapped arguments); including large blobs or buffers that exceed payload size limits; passing undefined/null where a scalar is required.

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/55f31bfe4e0718d8. Report an issue: GitHub.

Appendix: source

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

    }
    return capsule;
  }

  /**
   * Serialize cooperating appenders and validate current disk state under lock.
   * A partial I/O failure is preserved for diagnosis, never silently rolled back.
   */
  append(lineage, kind, payload = {}, options = {}) {
    return withAppendLock(this.dir, () => {
      const state = readCapsule(this.dir);
      if (!state.ok) throw new CapsuleError(state.code, state.reason, { failed_at: state.failed_at });
      if (!envelope.LINEAGES.includes(lineage)) {
        throw new CapsuleError('capsule.bad_lineage', `unknown lineage ${lineage}`);
      }
      const effectClass = options.effect_class || 'SE0';
      const { payload: clean, dropped, findings, errors: payloadErrors } = envelope.redactPayload(payload, options);
      if (payloadErrors.length > 0) {
        throw new CapsuleError('capsule.payload_invalid', payloadErrors.join('; '));
      }
      if (findings.length > 0) {
        throw new CapsuleError('capsule.secret_canary', `payload tripped secret canary ${findings[0].canary} at ${findings[0].path}`, { findings });
      }
      if (dropped.length > 0 && options.strict !== false) {
        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,

View on GitHub (pinned to 8321021c54)