GoogleChrome/lighthouse · error · LighthouseError
NO_LCP
NO_LCP
Error message
The page did not display content that qualifies as a Largest Contentful Paint (LCP). Ensure the page has a valid LCP element and then try again. ({errorCode}) What it means
Thrown as a LighthouseError with code NO_LCP when LCPImageRecord.compute_() finds that processedNavigation.timings.largestContentfulPaint is undefined. This means the page never produced a Largest Contentful Paint event during the trace, so there is no LCP image to associate. The LCP metric itself would also fail to compute for the same reason.
Solutions
- Ensure the page has visible content above the fold before the trace completes
- Verify Chrome was not run with --headless in a mode that suppresses paint events, or use --headless=new
- Check that the trace includes the 'disabled-by-default-largestContentfulPaint' category if collecting traces manually
- Run the Lighthouse audit again after confirming the page renders content
Defensive patterns
Strategy: try-catch
Validate before calling
// Check for LCP timing before requesting LCPImageRecord
const processedNavigation = await ProcessedNavigation.request(trace, context);
if (processedNavigation.timings.largestContentfulPaint === undefined) {
// No LCP — skip image record computation
return undefined;
} Type guard
/** @type {(nav: LH.Artifacts.ProcessedNavigation) => nav is LH.Artifacts.ProcessedNavigation & {timings: {largestContentfulPaint: number}}} */
function hasLCP(nav) {
return typeof nav.timings.largestContentfulPaint === 'number';
} Try / catch
try {
const lcpRecord = await LCPImageRecord.request(data, context);
} catch (e) {
if (e instanceof LighthouseError && e.code === 'NO_LCP') {
// Page has no LCP element — skip LCP image analysis
return;
}
throw e;
} Prevention
- Ensure the page renders visible content above the fold before trace capture ends
- Use --headless=new or headed Chrome to preserve paint event capture
- Include 'disabled-by-default-largestContentfulPaint' in trace categories when collecting manually
- Pre-check processedNavigation.timings.largestContentfulPaint before requesting LCPImageRecord
When it happens
Trigger: Calling LCPImageRecord.request() on a trace where the browser never emitted an LCP candidate event. This happens on pages with no visible content at load, pages that load in a hidden tab, or pages where the LCP polyfill/event was not captured in the trace.
Common situations: Auditing a page behind a login wall that renders no content. Headless Chrome running with viewport visibility off. A page that renders everything via JavaScript that fails to execute. Trace collected too early or with an incomplete trace category set.
Related errors
AI-assisted analysis of GoogleChrome/lighthouse@9515cd4e58 (2026-08-13).
Data as JSON: /api/errors/5acc281f34a27a28.
Report an issue: GitHub.
Appendix: source
Thrown at core/computed/lcp-image-record.js:29
/**
* @fileoverview Match the LCP event with the paint event to get the request of the image actually painted.
* This could differ from the `ImageElement` associated with the nodeId if e.g. the LCP
* was a pseudo-element associated with a node containing a smaller background-image.
*/
class LCPImageRecord {
/**
* @param {{trace: LH.Trace, devtoolsLog: LH.DevtoolsLog}} data
* @param {LH.Artifacts.ComputedContext} context
* @return {Promise<LH.Artifacts.NetworkRequest|undefined>}
*/
static async compute_(data, context) {
const {trace, devtoolsLog} = data;
const networkRecords = await NetworkRecords.request(devtoolsLog, context);
const processedNavigation = await ProcessedNavigation.request(trace, context);
if (processedNavigation.timings.largestContentfulPaint === undefined) {
throw new LighthouseError(LighthouseError.errors.NO_LCP);
}
// Use main-frame-only LCP to match the metric value.
const lcpEvent = processedNavigation.largestContentfulPaintEvt;
if (!lcpEvent) return;
const lcpImagePaintEvent = trace.traceEvents.filter(e => {
return e.name === 'LargestImagePaint::Candidate' &&
e.args.frame === lcpEvent.args.frame &&
e.args.data?.DOMNodeId === lcpEvent.args.data?.nodeId &&
e.args.data?.size === lcpEvent.args.data?.size;
// Get last candidate, in case there was more than one.
}).sort((a, b) => b.ts - a.ts)[0];
const lcpUrl = lcpImagePaintEvent?.args.data?.imageUrl;
if (!lcpUrl) return;
const candidates = networkRecords.filter(record => {View on GitHub (pinned to 9515cd4e58)