GoogleChrome/lighthouse · error · LighthouseError

NO_TTI_CPU_IDLE_PERIOD

NO_TTI_CPU_IDLE_PERIOD

Error message

Your page took too long to load. Please follow the opportunities in the report to reduce your page load time, and then try re-running Lighthouse. ({errorCode})

What it means

Thrown as a LighthouseError with code NO_TTI_CPU_IDLE_PERIOD when findOverlappingQuietPeriods() cannot find any 5-second window where the main thread has no task longer than 50ms (a CPU quiet period). This fires when cpuCandidate is falsy after the search loop, meaning the main thread never stopped being busy for long enough to declare interactivity. Time to Interactive cannot be computed without a CPU quiet period.

Source

Thrown at core/computed/metrics/interactive.js:134

        } else {
          networkCandidate = networkQueue.shift();
        }
      } else {
        // Network starts later than CPU, window must be contained by CPU or we check the next
        if (cpuCandidate.end >= networkCandidate.start + REQUIRED_QUIET_WINDOW) {
          return {
            cpuQuietPeriod: cpuCandidate,
            networkQuietPeriod: networkCandidate,
            cpuQuietPeriods,
            networkQuietPeriods,
          };
        } else {
          cpuCandidate = cpuQueue.shift();
        }
      }
    }

    throw new LighthouseError(
      cpuCandidate
        ? LighthouseError.errors.NO_TTI_NETWORK_IDLE_PERIOD
        : LighthouseError.errors.NO_TTI_CPU_IDLE_PERIOD
    );
  }

  /**
   * @param {LH.Artifacts.NavigationMetricComputationData} data
   * @param {LH.Artifacts.ComputedContext} context
   * @return {Promise<LH.Artifacts.LanternMetric>}
   */
  static computeSimulatedMetric(data, context) {
    const metricData = NavigationMetric.getMetricComputationInput(data);
    return LanternInteractive.request(metricData, context);
  }

  /**
   * @param {LH.Artifacts.NavigationMetricComputationData} data

View on GitHub (pinned to 9515cd4e58)

Solutions

  1. Break up long JavaScript tasks into smaller chunks using setTimeout, requestIdleCallback, or scheduler.yield()
  2. Move heavy computation to a Web Worker to free the main thread
  3. Eliminate unnecessary setInterval/setTimeout loops or throttle them
  4. Audit and reduce third-party scripts that run continuously on the main thread
Defensive patterns

Strategy: try-catch

Try / catch

try {
  const tti = await Interactive.request(metricData, context);
} catch (e) {
  if (e instanceof LighthouseError && e.code === 'NO_TTI_CPU_IDLE_PERIOD') {
    // Main thread never quiet for 5s — report TTI as N/A
    return { notApplicable: true, reason: 'NO_TTI_CPU_IDLE_PERIOD' };
  }
  throw e;
}

Prevention

When it happens

Trigger: The Interactive metric loops through long tasks (>= 50ms). If long tasks are so frequent that no 5-second gap exists between them, no CPU quiet period is ever found, and the throw uses NO_TTI_CPU_IDLE_PERIOD (the ternary in the throw selects this code when cpuCandidate is falsy).

Common situations: Pages with heavy JavaScript execution, infinite animation loops, requestAnimationFrame storms, or continuous timer-based work (setInterval). Common on SPAs with heavy re-renders or pages with poorly optimized third-party scripts that constantly execute on the main thread.

Related errors


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