affaan-m/ECC · error · Error

${source} is missing the catalog count description

Error message

${source} is missing the catalog count description

What it means

After JSON-parsing succeeds, `parseCatalogDescriptionExpectations` calls `getDescription(parsed)` and checks `typeof description !== 'string'`. For plugin.json this reads `parsed.description`; for marketplace.json it reads `parsed.plugins?.[0]?.description`. If the field is missing, undefined, null, or a non-string, the throw fires with `${source} is missing the catalog count description`. This is distinct from error 32 (which fires when the description string exists but lacks the count pattern).

Source

Thrown at scripts/ci/catalog.js:341

      expected: Number(match[1]),
      source: `${pattern.source} (${pattern.category})`
    });
  }

  return expectations;
}

function parseCatalogDescriptionExpectations(content, source, getDescription) {
  let parsed;
  try {
    parsed = JSON.parse(content);
  } catch (error) {
    throw new Error(`${source} is not valid JSON: ${error.message}`);
  }

  const description = getDescription(parsed);
  if (typeof description !== 'string') {
    throw new Error(`${source} is missing the catalog count description`);
  }

  const match = description.match(/(\d+)\s+agents,\s+(\d+)\s+skills,\s+(\d+)\s+legacy command shims?/i);
  if (!match) {
    throw new Error(`${source} is missing the catalog count description`);
  }

  return [
    { category: 'agents', mode: 'exact', expected: Number(match[1]), source },
    { category: 'skills', mode: 'exact', expected: Number(match[2]), source },
    { category: 'commands', mode: 'exact', expected: Number(match[3]), source },
  ];
}

function evaluateExpectations(catalog, expectations) {
  return expectations.map(expectation => {
    const actual = catalog[expectation.category].count;
    const ok = expectation.mode === 'minimum'

View on GitHub (pinned to 01e15490f0)

Solutions

  1. For plugin.json: ensure a top-level `"description": "..."` string key exists.
  2. For marketplace.json: ensure `plugins[0].description` is a string — verify the plugins array is non-empty and index 0 is the intended plugin.
  3. The description string must contain the count pattern `N agents, N skills, N legacy command shims` (see error 32) once restored.
  4. Run `node scripts/ci/catalog.js --write` to populate/sync the description counts after restoring the field.

Example fix

// before (.claude-plugin/marketplace.json — empty plugins array)
{
  "plugins": []
}

// after
{
  "plugins": [
    {
      "name": "ecc",
      "description": "ECC plugin — 68 agents, 284 skills, 94 legacy command shims"
    }
  ]
}
Defensive patterns

Strategy: validation

Validate before calling

const fs = require('fs');
function checkDesc(file, getterDesc) {
  const parsed = JSON.parse(fs.readFileSync(file, 'utf8'));
  let obj = parsed;
  for (const key of getterDesc) {
    if (obj == null || typeof obj !== 'object') { console.error(`${file}: missing ${getterDesc.join('.')}`); process.exit(1); }
    obj = obj[key];
  }
  if (typeof obj !== 'string') { console.error(`${file}: ${getterDesc.join('.')} is not a string`); process.exit(1); }
}
checkDesc('.claude-plugin/plugin.json', ['description']);
checkDesc('.claude-plugin/marketplace.json', ['plugins', '0', 'description']);

Type guard

function hasDescriptionField(parsed, marketplace) {
  if (!marketplace) return typeof parsed?.description === 'string';
  return Array.isArray(parsed?.plugins) && parsed.plugins.length > 0 && typeof parsed.plugins[0]?.description === 'string';
}

Try / catch

try {
  runCatalogCheck();
} catch (error) {
  if (/is missing the catalog count description/i.test(error.message)) {
    console.error('Add a string description field (plugin.json: description; marketplace.json: plugins[0].description) containing the count pattern.');
  }
  throw error;
}

Prevention

When it happens

Trigger: Fires when `.claude-plugin/plugin.json` has no `description` key, or `.claude-plugin/marketplace.json` has no `plugins` array, an empty `plugins` array, or `plugins[0]` has no `description` key. Also fires if description is explicitly null or a number.

Common situations: plugin.json is regenerated by a scaffolder that omits description. marketplace.json's plugins array is reordered and index 0 now points at a different plugin without a description. The description field is renamed (e.g. to `summary`). The plugins array is empty after a cleanup.

Related errors


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