mastra-ai/mastra · error

This workflow run is still running, cannot time travel

Error message

This workflow run is still running, cannot time travel

What it means

Thrown by the workflow time-travel API when the loaded snapshot's status is still 'running'. Time travel requires a terminal or suspended state because mutating the step history of an in-flight run would conflict with its active execution. The library refuses to rewind a run that the engine still considers live.

Source

Thrown at packages/core/src/workflows/workflow.ts:4882

    actor?: ActorSignal;
  } & Partial<ObservabilityContext>): Promise<WorkflowResult<TState, TInput, TOutput, TSteps>> {
    const observabilityContext = resolveObservabilityContext(rest);
    if (!stepParam || (Array.isArray(stepParam) && stepParam.length === 0)) {
      throw new Error('Step is required and must be a valid step or array of steps');
    }

    const workflowsStore = await this.#mastra?.getStorage()?.getStore('workflows');
    const snapshot = await workflowsStore?.loadWorkflowSnapshot({
      workflowName: this.workflowId,
      runId: this.runId,
    });

    if (!snapshot) {
      throw new Error(`Snapshot not found for run ${this.runId}`);
    }

    if (snapshot.status === 'running') {
      throw new Error('This workflow run is still running, cannot time travel');
    }

    let steps: string[];
    let newStepParam = stepParam;
    if (typeof stepParam === 'string') {
      newStepParam = stepParam.split('.');
    }
    steps = (Array.isArray(newStepParam) ? newStepParam : [newStepParam]).map(step =>
      typeof step === 'string' ? step : step?.id,
    );

    let inputDataToUse = inputData;

    if (inputDataToUse && steps.length === 1) {
      inputDataToUse = await this._validateTimetravelInputData(inputData, this.workflowSteps[steps[0]!]!);
    }

    const timeTravelData = createTimeTravelExecutionParams({

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Wait for the run to reach a terminal/suspended status, or await the run's completion promise before time traveling.
  2. If the run is actually dead (crash/restart), manually mark the stale snapshot status (e.g., 'failed') in the store, then retry.
  3. Resume a suspended run via resume() instead of time traveling.
  4. Cancel/stop the run through the workflow API so its snapshot status is updated, then time travel.

Example fix

// before
await workflow.timeTravel(runId, 'step1'); // throws if still running
// after
const snapshot = await store.loadWorkflowSnapshot({ workflowName: wf.id, runId });
if (snapshot.status === 'running') await runCompletion; // or cancel the run first
await workflow.timeTravel(runId, 'step1');
Defensive patterns

Strategy: try-catch

Validate before calling

const snapshot = await store.loadWorkflowSnapshot({ workflowName: workflowId, runId });
if (snapshot?.status === 'running') throw new Error(`Run ${runId} still in progress`);

Try / catch

try { await workflow.timeTravel(runId, step); } catch (e) { if ((e as Error).message.includes('still running')) { await waitForRunTerminal(runId); /* retry once */ } else throw e; }

Prevention

When it happens

Trigger: Calling time travel on a run whose persisted snapshot has status === 'running' — i.e., the run hasn't finished (or a previous run crashed without updating its snapshot status to a terminal value).

Common situations: Time traveling concurrently with an active run; a crashed/restarted server left stale snapshots with status 'running'; a hung step (e.g., awaiting an external event or long suspend) keeps the run marked running.

Related errors


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/14a34a0caf85e100. Report an issue: GitHub.