affaan-m/ECC · error · Error

Install module ${moduleId} has unsupported targets: ${unsupp

Error message

Install module ${moduleId} has unsupported targets: ${unsupportedTargets.join(', ')}

What it means

After normalisation, every target id must be in SUPPORTED_INSTALL_TARGETS (claude, claude-project, cursor, antigravity, codex, gemini, opencode, codebuddy, joycode, qwen, zed, hermes, openclaw, kimi). Any target not in that list is collected into unsupportedTargets and the whole module is rejected with the offending ids listed.

Source

Thrown at scripts/lib/install-manifests.js:244

function readModuleTargetsOrThrow(module) {
  const moduleId = module && module.id ? module.id : '<unknown>';
  const targets = module && module.targets;

  if (!Array.isArray(targets)) {
    throw new Error(`Install module ${moduleId} has invalid targets; expected an array of supported target ids`);
  }

  const normalizedTargets = targets.map(target => (
    typeof target === 'string' ? target.trim() : ''
  ));

  if (normalizedTargets.some(target => target.length === 0)) {
    throw new Error(`Install module ${moduleId} has invalid targets; expected an array of supported target ids`);
  }

  const unsupportedTargets = normalizedTargets.filter(target => !SUPPORTED_INSTALL_TARGETS.includes(target));
  if (unsupportedTargets.length > 0) {
    throw new Error(
      `Install module ${moduleId} has unsupported targets: ${unsupportedTargets.join(', ')}`
    );
  }

  return normalizedTargets;
}

function assertKnownModuleIds(moduleIds, manifests) {
  const unknownModuleIds = dedupeStrings(moduleIds)
    .filter(moduleId => !manifests.modulesById.has(moduleId));

  if (unknownModuleIds.length === 1) {
    throw new Error(`Unknown install module: ${unknownModuleIds[0]}`);
  }

  if (unknownModuleIds.length > 1) {
    throw new Error(`Unknown install modules: ${unknownModuleIds.join(', ')}`);
  }

View on GitHub (pinned to 01e15490f0)

Solutions

  1. Compare each id in the message against SUPPORTED_INSTALL_TARGETS (case-sensitive, lowercase, hyphenated).
  2. Fix typos and casing in manifests/install-modules.json.
  3. If the id is genuinely new, upgrade the installer package so SUPPORTED_INSTALL_TARGETS includes it.
  4. Remove targets the installer cannot service rather than leaving stale ids.

Example fix

// before: { "id": "my-mod", "targets": ["claude", "Cluade"] }
// after: { "id": "my-mod", "targets": ["claude"] }
Defensive patterns

Strategy: validation

Validate before calling

const SUPPORTED = new Set(['claude','claude-project','cursor','antigravity','codex','gemini','opencode','codebuddy','joycode','qwen','zed','hermes','openclaw','kimi']);
function unsupportedModuleTargets(module) {
  return (module.targets || []).filter(t => !SUPPORTED.has(t));
}
// before load: assert manifests.modules.every(m => unsupportedModuleTargets(m).length === 0)

Type guard

function isSupportedTarget(value) {
  return SUPPORTED.has(value);
}

Try / catch

try {
  loadInstallManifests({ repoRoot });
} catch (err) {
  if (/has unsupported targets/.test(err.message)) {
    // extract ids from message, fix manifest, retry
  } else throw err;
}

Prevention

When it happens

Trigger: install-modules.json declares a target the installer does not recognise — typo ('Cluade'), removed id ('vscodium'), or a forward reference to a target added in a newer installer version. Triggered at manifest load for any module consumed by the install pipeline.

Common situations: Author added a new target id but the running installer predates it; renamed target id (old name still in manifest); case mismatch ('Claude' vs 'claude'); copy-paste from another harness's docs.

Related errors


AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13). Data as JSON: /api/errors/baee7174a27469cb. Report an issue: GitHub.