GoogleChrome/lighthouse · error · Error
Timespan already in progress
Error message
Timespan already in progress
What it means
State-machine guard in UserFlow.navigate(). The UserFlow class enforces that only one gathering operation (navigation or timespan) can be active at a time. navigate() requires both currentTimespan and currentNavigation to be undefined. This throw fires when a timespan is still active — startTimespan() was called but endTimespan() has not completed.
Source
Thrown at core/user-flow.js:127
/**
* @param {LH.Gatherer.GatherResult} gatherResult
* @param {LH.UserFlow.StepFlags} [flags]
*/
_addGatherStep(gatherResult, flags) {
const gatherStep = {
artifacts: gatherResult.artifacts,
flags,
};
this._gatherSteps.push(gatherStep);
this._gatherStepRunnerOptions.set(gatherStep, gatherResult.runnerOptions);
}
/**
* @param {LH.NavigationRequestor} requestor
* @param {LH.UserFlow.StepFlags} [flags]
*/
async navigate(requestor, flags) {
if (this.currentTimespan) throw new Error('Timespan already in progress');
if (this.currentNavigation) throw new Error('Navigation already in progress');
const nextFlags = this._getNextNavigationFlags(flags);
const gatherResult = await navigationGather(this._page, requestor, {
config: this._options?.config,
flags: nextFlags,
});
this._addGatherStep(gatherResult, nextFlags);
}
/**
* This is an alternative to `navigate()` that can be used to analyze a navigation triggered by user interaction.
* For more on user triggered navigations, see https://github.com/GoogleChrome/lighthouse/blob/main/docs/user-flows.md#triggering-a-navigation-via-user-interactions.
*
* @param {LH.UserFlow.StepFlags} [stepOptions]
*/
async startNavigation(stepOptions) {View on GitHub (pinned to 9515cd4e58)
Solutions
- Call flow.endTimespan() before flow.navigate() or flow.startNavigation()
- Wrap timespan logic in try/finally to guarantee endTimespan() runs even on error
- Check flow.currentTimespan before navigating — if set, end the timespan first
Example fix
// before — navigate while timespan active await flow.startTimespan(); // ... interactions ... await flow.navigate(url); // throws // after — end timespan first await flow.startTimespan(); // ... interactions ... await flow.endTimespan(); await flow.navigate(url);
Defensive patterns
Strategy: validation
Validate before calling
if (flow.currentTimespan) {
await flow.endTimespan();
}
await flow.navigate(url); Type guard
/** @param {UserFlow} flow @returns {boolean} */
function isTimespanActive(flow) {
return flow.currentTimespan != null;
} Try / catch
try {
await flow.navigate(url);
} catch (e) {
if (e.message === 'Timespan already in progress') {
await flow.endTimespan();
await flow.navigate(url);
} else throw e;
} Prevention
- Always pair startTimespan() with endTimespan() using try/finally
- Check flow.currentTimespan before calling navigate or startNavigation
- End one gathering operation before starting another
When it happens
Trigger: Calling flow.navigate(url) or flow.startNavigation() after flow.startTimespan() without calling flow.endTimespan() first. The currentTimespan property is still set from the prior startTimespan call.
Common situations: Forgot to call endTimespan() before navigating. An exception in user interaction code between startTimespan and endTimespan prevented the end call. Using navigate() instead of endTimespan() to close a timespan by mistake.
Related errors
- Navigation already in progress
- No navigation in progress
- No timespan in progress
- NO_DCL
- unexpected response: ${response.statusCode} ${response.statu
AI-assisted analysis of GoogleChrome/lighthouse@9515cd4e58 (2026-08-13).
Data as JSON: /api/errors/b030fd24cc03b8e6.
Report an issue: GitHub.