GoogleChrome/lighthouse · error · Error

${pluginName} has an invalid category manualDescription.

Error message

${pluginName} has an invalid category manualDescription.

What it means

Thrown by ConfigPlugin._parseCategory while validating a plugin category's 'manualDescription' field. Like description, manualDescription is optional but, when present, must satisfy i18n.isStringOrIcuMessage (a string or ICU message). It is the text shown for manual categories in the report. Any other type fails.

Source

Thrown at core/config/config-plugin.js:158

    const {
      title,
      description,
      manualDescription,
      auditRefs: auditRefsJson,
      supportedModes,
      ...invalidRest
    } = categoryJson;

    assertNoExcessProperties(invalidRest, pluginName, 'category');

    if (!i18n.isStringOrIcuMessage(title)) {
      throw new Error(`${pluginName} has an invalid category tile.`);
    }
    if (!i18n.isStringOrIcuMessage(description) && description !== undefined) {
      throw new Error(`${pluginName} has an invalid category description.`);
    }
    if (!i18n.isStringOrIcuMessage(manualDescription) && manualDescription !== undefined) {
      throw new Error(`${pluginName} has an invalid category manualDescription.`);
    }
    if (!isArrayOfGatherModes(supportedModes) && supportedModes !== undefined) {
      throw new Error(
        `${pluginName} supportedModes must be an array, ` +
        `valid array values are "navigation", "timespan", and "snapshot".`
      );
    }
    const auditRefs = ConfigPlugin._parseAuditRefsList(auditRefsJson, pluginName);

    return {
      title,
      auditRefs,
      description: description,
      manualDescription: manualDescription,
      supportedModes,
    };
  }

View on GitHub (pinned to 9515cd4e58)

Solutions

  1. Set manualDescription to a single string combining your manual steps, e.g. manualDescription: 'Step 1. ... Step 2. ...'
  2. Use an i18n ICU message object if the text needs localization.
  3. Remove the manualDescription key if you do not need manual instructions.

Example fix

// before
category: {title: 'Manual', manualDescription: ['Run axe','Check contrast'], auditRefs: [...]}
// after
category: {title: 'Manual', manualDescription: 'Run axe. Then check contrast manually.', auditRefs: [...]}
Defensive patterns

Strategy: validation

Validate before calling

const i18n = require('lighthouse/core/lib/i18n/i18n.js');
if (cat.manualDescription !== undefined && !i18n.isStringOrIcuMessage(cat.manualDescription)) {
  throw new TypeError('manualDescription must be a single string');
}

Type guard

function isValidManualDescription(v) {
  return v === undefined || typeof v === 'string';
}

Try / catch

try {
  await ConfigPlugin.parsePlugin(plugin, name);
} catch (e) {
  if (/invalid category manualDescription/.test(e.message)) console.error('manualDescription must be one string');
  throw e;
}

Prevention

When it happens

Trigger: A plugin category sets manualDescription to a non-string value, e.g. category: {title, manualDescription: ['step 1','step 2'], auditRefs:[...]}. Because it is not undefined and not a string/IcuMessage, config-plugin.js:158 throws.

Common situations: Treating manualDescription as an array of steps (it must be a single string). Setting it to an object or number. Migrating from an older plugin schema and leaving a stray value.

Related errors


AI-assisted analysis of GoogleChrome/lighthouse@9515cd4e58 (2026-08-13). Data as JSON: /api/errors/4017d16fa1f19832. Report an issue: GitHub.