affaan-m/ECC · error · Error

target harnesses must contain at least one harness or "all".

Error message

target harnesses must contain at least one harness or "all".

What it means

After normalizing memory.targetHarnesses through uniqueStrings (which also deduplicates, enforces a max count of MAX_TARGETS, and slug-validates each entry), normalizeMemory requires at least one target harness entry — or the special value 'all'. An empty list would make the memory invisible to every harness, so it is rejected.

Solutions

  1. Include at least one harness slug in targetHarnesses, e.g. ['claude'] or ['claude', 'codex'].
  2. Use ['all'] if the memory should apply to every harness.
  3. Check that entries are valid slugs (validateSlug) — invalid entries may fail earlier or be filtered, leaving the list empty.
  4. Verify the frontmatter field is present at all; a missing targetHarnesses field yields an empty normalized list.

Example fix

// before
{
  schema: 1,
  id: 'deploy-notes',
  title: 'Deploy notes',
  targetHarnesses: []
}

// after
{
  schema: 1,
  id: 'deploy-notes',
  title: 'Deploy notes',
  targetHarnesses: ['all']
}
Defensive patterns

Strategy: validation

Validate before calling

const harnesses = Array.isArray(input.targetHarnesses)
  ? input.targetHarnesses.filter(h => typeof h === 'string' && h.length > 0)
  : [];
if (harnesses.length === 0) input.targetHarnesses = ['all'];

Type guard

const hasTargetHarnesses = (m) => Array.isArray(m.targetHarnesses) && m.targetHarnesses.length > 0;

Try / catch

try {
  saveMemory(memory);
} catch (err) {
  if (err.message.includes('target harnesses must contain at least one')) {
    saveMemory({ ...memory, targetHarnesses: ['all'] });
  } else throw err;
}

Prevention

When it happens

Trigger: Saving a memory with targetHarnesses: [] (or omitting it so it resolves to an empty list), or passing targetHarnesses: ['all'] alongside invalid entries that are filtered out leaving zero valid harnesses.

Common situations: Hand-written frontmatter with `targetHarnesses: []`; tooling that strips invalid slugs and leaves an empty array; a config template where the harness list placeholder was never filled in.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


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

Appendix: source

Thrown at scripts/lib/memory-vault-format.js:172

  }
  if (Buffer.byteLength(normalized, 'utf8') > MAX_BODY_BYTES) {
    throw new Error(`memory body is too large (maximum ${MAX_BODY_BYTES} bytes).`);
  }
  return normalized;
}

function normalizeMemory(memory) {
  if (!memory || typeof memory !== 'object' || Array.isArray(memory)) {
    throw new Error('memory must be an object.');
  }

  const targetHarnesses = uniqueStrings(memory.targetHarnesses, {
    label: 'target harnesses',
    limit: MAX_TARGETS,
    validator: value => validateSlug(value, 'target harness'),
  });
  if (targetHarnesses.length === 0) {
    throw new Error('target harnesses must contain at least one harness or "all".');
  }

  if (memory.schema !== MEMORY_SCHEMA_VERSION) {
    throw new Error('Unsupported memory schema.');
  }

  return {
    schema: memory.schema,
    id: validateMemoryId(memory.id),
    title: asNonEmptyString(memory.title, 'memory title', MAX_TITLE_CHARS),
    kind: validateEnum(memory.kind, MEMORY_KINDS, 'memory kind'),
    scope: validateEnum(memory.scope, MEMORY_SCOPES, 'memory scope'),
    trust: validateEnum(memory.trust, MEMORY_TRUST_STATES, 'memory trust'),
    status: validateEnum(memory.status, MEMORY_STATUSES, 'memory status'),
    sourceHarness: validateSlug(memory.sourceHarness, 'source harness'),
    targetHarnesses,
    tags: uniqueStrings(memory.tags, {
      label: 'tags',

View on GitHub (pinned to 8321021c54)