affaan-m/ECC · error

Unknown install module

Error message

Unknown install module: ${unknownModuleIds[0]}

What it means

Thrown by assertKnownModuleIds when exactly one requested module id does not exist in the loaded manifests' modulesById map. Callers validate user-supplied or profile-supplied module selections against manifests loaded from install-modules.json. The singular variant fires when exactly one id is unknown.

Solutions

  1. Check the module id in the error and correct the typo in your selection/profile.
  2. List valid module ids from manifests/install-modules.json and pick the current name.
  3. If the module was renamed in a recent update, update your config/commands to the new id.
  4. If the id is legacy, rely on resolveLegacyCompatibilitySelection mapping or remove the legacy reference.
  5. Run npm run catalog:sync if the module exists in skills/ but was never added to the manifest.

Example fix

// before
validateInstallModuleIds(['tdd-workflo'])

// after
validateInstallModuleIds(['tdd-workflow'])
Defensive patterns

Strategy: validation

Validate before calling

const manifests = loadInstallManifests();
const unknown = ids.filter(id => !manifests.modulesById.has(id));
if (unknown.length) throw new Error(`Fix these ids before calling: ${unknown.join(', ')}`);

Type guard

function areKnownModuleIds(ids, manifests) {
  return Array.isArray(ids) && ids.every(id => manifests.modulesById.has(id));
}

Try / catch

try {
  validateInstallModuleIds(userIds);
} catch (err) {
  if (/^Unknown install module: /.test(err.message)) {
    console.error(`Invalid module id in config: ${err.message}`);
    process.exitCode = 1;
  } else throw err;
}

Prevention

When it happens

Trigger: validateInstallModuleIds() or resolveLegacyCompatibilitySelection() invoked with a module id list containing exactly one id absent from install-modules.json, e.g. validateInstallModuleIds(['my-module']) where 'my-module' is not defined in the manifest.

Common situations: Typo in a module id on the CLI or in a profile config; referencing a module that was renamed or removed in a newer ECC version; copying a module id from stale docs; legacy selection strings pointing at retired modules.

Understand the failure class

Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.

Related errors


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

Appendix: source

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

    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(', ')}`);
  }
}

function intersectTargets(modules) {
  if (!Array.isArray(modules) || modules.length === 0) {
    return [];
  }

  return SUPPORTED_INSTALL_TARGETS.filter(target => (
    modules.every(module => Array.isArray(module.targets) && module.targets.includes(target))
  ));
}

function getManifestPaths(repoRoot = DEFAULT_REPO_ROOT) {

View on GitHub (pinned to 8321021c54)