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
- Set manualDescription to a single string combining your manual steps, e.g. manualDescription: 'Step 1. ... Step 2. ...'
- Use an i18n ICU message object if the text needs localization.
- 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
- Write manualDescription as a single concatenated string, not an array of steps.
- Validate optional category fields as string-or-omitted in your plugin tests.
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
- ${pluginName} has an invalid category description.
- ${pluginName} has an invalid group title.
- ${pluginName} has an invalid group description.
- ${pluginName} supportedModes must be an array, valid array v
- ${pluginName} groups json is not defined as an object.
AI-assisted analysis of GoogleChrome/lighthouse@9515cd4e58 (2026-08-13).
Data as JSON: /api/errors/4017d16fa1f19832.
Report an issue: GitHub.