GoogleChrome/lighthouse · error

${auditName} has no audit() method.

Error message

${auditName} has no audit() method.

What it means

Thrown by assertValidAudit in validation.js. An audit implementation must provide an 'audit' method that is a function AND must override Audit.audit (the base placeholder). The check `implementation.audit === Audit.audit` catches subclasses that extend Audit but never define their own audit logic. auditName is the audit path or meta.id for context.

Source

Thrown at core/config/validation.js:88

    gatherer.getArtifact === BaseGatherer.prototype.getArtifact
  ) {
    throw new Error(`Gatherer for ${artifactDefn.id} did not define a "getArtifact" method.`);
  }
}

/**
 * Throws an error if the provided object does not implement the required properties of an audit
 * definition.
 * @param {LH.Config.AuditDefn} auditDefinition
 */
function assertValidAudit(auditDefinition) {
  const {implementation, path: auditPath} = auditDefinition;
  const auditName = auditPath ||
    implementation?.meta?.id ||
    'Unknown audit';

  if (typeof implementation.audit !== 'function' || implementation.audit === Audit.audit) {
    throw new Error(`${auditName} has no audit() method.`);
  }

  if (typeof implementation.meta.id !== 'string') {
    throw new Error(`${auditName} has no meta.id property, or the property is not a string.`);
  }

  if (!i18n.isStringOrIcuMessage(implementation.meta.title)) {
    throw new Error(`${auditName} has no meta.title property, or the property is not a string.`);
  }

  // If it'll have a ✔ or ✖ displayed alongside the result, it should have failureTitle
  const scoreDisplayMode = implementation.meta.scoreDisplayMode || Audit.SCORING_MODES.BINARY;
  if (
    !i18n.isStringOrIcuMessage(implementation.meta.failureTitle) &&
    scoreDisplayMode === Audit.SCORING_MODES.BINARY
  ) {
    throw new Error(`${auditName} has no meta.failureTitle and should.`);
  }

View on GitHub (pinned to 9515cd4e58)

Solutions

  1. Define a static audit(artifacts, context) method on your audit class returning {score, ...}.
  2. Ensure the method name is exactly 'audit'.
  3. Confirm your class extends Audit so the override check is valid.

Example fix

// before
class MyAudit extends Audit {
  static get meta() { return {id:'my-audit', title:'X', description:'Y', requiredArtifacts:[]}; }
  // no audit() method
}
// after
class MyAudit extends Audit {
  static get meta() { return {id:'my-audit', title:'X', description:'Y', requiredArtifacts:[]}; }
  static audit(artifacts) {
    return {score: artifacts.X ? 1 : 0};
  }
}
Defensive patterns

Strategy: type-guard

Validate before calling

const {Audit} = require('lighthouse/core/audits/audit.js');
function assertAuditMethod(impl) {
  if (typeof impl.audit !== 'function' || impl.audit === Audit.audit) {
    throw new TypeError(`Audit must override audit()`);
  }
}

Type guard

function implementsAudit(impl, Audit) {
  return typeof impl.audit === 'function' && impl.audit !== Audit.audit;
}

Try / catch

try { new Config(config, {configPath}); }
catch (e) { if (/has no audit\(\) method/.test(e.message)) console.error('Define static audit() on the audit class'); throw e; }

Prevention

When it happens

Trigger: A custom audit class extends Audit but does not declare a static/prototype audit method, so implementation.audit === Audit.audit. Or audit is set to a non-function. validation.js:88 throws.

Common situations: Writing a new audit and forgetting the audit() method. Copying an audit scaffold without filling in audit(). Naming the method differently (e.g. 'run' from an older API).

Related errors


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