affaan-m/ECC · error · Error

Harness capability catalog contains duplicate install target

Error message

Harness capability catalog contains duplicate install target ids

What it means

harness-capabilities.js runs validateCatalog() at require() time. This check flattens every harness entry's targetIds and throws if any install-target id appears more than once across the catalog — each target must be owned by exactly one harness entry. A throw here crashes on module load, so every consumer of the file fails immediately.

Source

Thrown at scripts/lib/harness-capabilities.js:264

  }
}

function expectedRootForAdapter(adapter) {
  const homeDir = path.resolve('/__ecc_catalog_home__');
  const projectRoot = path.resolve('/__ecc_catalog_project__');
  const absoluteRoot = adapter.resolveRoot({ homeDir, projectRoot });
  const baseRoot = adapter.kind === 'home' ? homeDir : projectRoot;
  const prefix = adapter.kind === 'home' ? '~/' : './';
  return `${prefix}${path.relative(baseRoot, absoluteRoot).replace(/\\/g, '/')}`;
}

function validateCatalog() {
  const adapters = listInstallTargetAdapters();
  const adapterByTarget = new Map(adapters.map(adapter => [adapter.target, adapter]));
  const catalogTargetIds = HARNESS_CAPABILITIES.flatMap(harness => harness.targetIds);

  if (new Set(catalogTargetIds).size !== catalogTargetIds.length) {
    throw new Error('Harness capability catalog contains duplicate install target ids');
  }

  const supported = [...SUPPORTED_INSTALL_TARGETS].sort();
  const registered = adapters.map(adapter => adapter.target).sort();
  const catalogued = [...catalogTargetIds].sort();
  if (
    JSON.stringify(catalogued) !== JSON.stringify(supported)
    || JSON.stringify(catalogued) !== JSON.stringify(registered)
  ) {
    throw new Error('Harness capability catalog is out of sync with install targets');
  }

  for (const harness of HARNESS_CAPABILITIES) {
    for (const declaredScope of harness.scopes) {
      const adapter = adapterByTarget.get(declaredScope.targetId);
      if (!adapter || expectedRootForAdapter(adapter) !== declaredScope.root) {
        throw new Error(
          `Harness capability root is out of sync for target ${declaredScope.targetId}`

View on GitHub (pinned to d8409a4b08)

Solutions

  1. Search HARNESS_CAPABILITIES for the duplicated target id and remove it from all but one harness's targetIds array
  2. Verify the fix loads: `node -e "require('./scripts/lib/harness-capabilities.js')"` must exit silently
  3. Add/keep a unit test asserting Set(targetIds).size === targetIds.length so CI catches it before review
  4. When moving a target between harnesses, delete the old reference in the same commit

Example fix

// before
{ id: 'vscode-family', targetIds: ['cursor', 'codebuddy'] },
{ id: 'other', targetIds: ['cursor', 'qwen'] },

// after
{ id: 'vscode-family', targetIds: ['cursor', 'codebuddy'] },
{ id: 'other', targetIds: ['qwen'] },
Defensive patterns

Strategy: validation

Validate before calling

// CI guard: catalog target ids must be unique across harnesses
const { HARNESS_CAPABILITIES } = require('./scripts/lib/harness-capabilities.js');
const ids = HARNESS_CAPABILITIES.flatMap(h => h.targetIds);
if (new Set(ids).size !== ids.length) {
  const dup = ids.find((id, i) => ids.indexOf(id) !== i);
  throw new Error(`Duplicate targetId in catalog: ${dup}`);
}

Prevention

When it happens

Trigger: A contributor edits HARNESS_CAPABILITIES and adds a targetId (e.g. 'cursor') to a second harness entry that already lists it elsewhere. Any `require('./harness-capabilities.js')` — including unrelated CLI entry points — then throws during startup.

Common situations: Copy-pasting an existing harness entry as a template and forgetting to replace its targetIds; a git merge that keeps the same target in two entries; refactoring that moves a target between harnesses without deleting the old reference.

Related errors


AI-assisted analysis of affaan-m/ECC@d8409a4b08 (2026-08-26). Data as JSON: /api/errors/93a38b81af1a93f2. Report an issue: GitHub.