mastra-ai/mastra · error

Cannot time travel to step '${targetStepId}': the step does

Error message

Cannot time travel to step '${targetStepId}': the step does not exist in the current execution graph. The workflow definition has likely changed since the run was recorded (renamed step, or an unnamed .map() step whose generated id changed across processes). Steps recorded in the snapshot: ${reportedIdsSuffix}. The stored snapshot has not been modified.

What it means

assertTimeTravelGraphMatchesSnapshot throws when the target step id for a time-travel operation does not exist in the current execution graph snapshot. It fires when targetEntryIndex === -1, meaning the workflow definition changed since the run was recorded (renamed step, or an unnamed .map() whose generated id differs across processes). The stored snapshot is left unmodified.

Source

Thrown at packages/core/src/workflows/utils.ts:374

}): void => {
  const { targetStepId, graph, snapshot, context } = params;
  const snapshotContext = (snapshot.context ?? {}) as Record<string, any>;
  const recordedStepIds = Object.keys(snapshotContext).filter(key => key !== 'input');

  // Empty snapshot context: nothing recorded, nothing to protect.
  if (recordedStepIds.length === 0) {
    return;
  }

  const targetEntryIndex = graph.steps.findIndex(entry => getStepIds(entry).includes(targetStepId));
  const reportedIds = recordedStepIds.slice(0, MAX_REPORTED_SNAPSHOT_IDS);
  const reportedIdsSuffix =
    recordedStepIds.length > MAX_REPORTED_SNAPSHOT_IDS
      ? `${reportedIds.join(', ')} (and ${recordedStepIds.length - MAX_REPORTED_SNAPSHOT_IDS} more)`
      : reportedIds.join(', ');

  if (targetEntryIndex === -1) {
    throw new Error(
      `Cannot time travel to step '${targetStepId}': the step does not exist in the current execution graph. ` +
        `The workflow definition has likely changed since the run was recorded (renamed step, or an unnamed .map() ` +
        `step whose generated id changed across processes). Steps recorded in the snapshot: ${reportedIdsSuffix}. ` +
        `The stored snapshot has not been modified.`,
    );
  }

  const hasRecordedEntry = (stepId: string) => snapshotContext[stepId] != null || context?.[stepId] != null;

  const missingStepIds: string[] = [];
  for (const [index, entry] of graph.steps.entries()) {
    if (index >= targetEntryIndex) {
      break;
    }
    // sleep / sleepUntil entries and zero-iteration foreach / loop entries may
    // legitimately have no recorded snapshot entry.
    if (entry.type === 'sleep' || entry.type === 'sleepUntil' || entry.type === 'foreach' || entry.type === 'loop') {
      continue;

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Use a target step id that matches one of the ids listed in the error message ('Steps recorded in the snapshot: ...').
  2. Give map() steps an explicit, stable id so generated ids do not change across processes.
  3. Align the workflow definition with the version that recorded the run, or re-record the run.
  4. If many ids are shown with '(and N more)', inspect the full snapshot to find valid ids.

Example fix

// before
.map({ id: undefined, execute: ... }) // generated id changes per process
timeTravel(runId, ['generated-unknown-step']);
// after
.map({ id: 'transform-items', execute: ... })
timeTravel(runId, ['transform-items']);
Defensive patterns

Strategy: validation

Validate before calling

function assertStepInSnapshot(stepId: string, snapshotIds: string[]) {
  if (!snapshotIds.includes(stepId)) throw new Error(`'${stepId}' not in snapshot; known: ${snapshotIds.join(', ')}`);
}

Try / catch

try {
  await workflow.timeTravel(runId, [targetStepId]);
} catch (e) {
  if ((e as Error).message.includes('does not exist in the current execution graph')) {
    const ids = (e as Error).message.match(/snapshot: (.+)\./)?.[1] ?? '';
    console.error(`Pick a valid step id from snapshot: ${ids}`);
  } else throw e;
}

Prevention

When it happens

Trigger: Calling createTimeTravelExecutionParams (which calls assertTimeTravelGraphMatchesSnapshot) with a targetStepId not present in the recorded snapshot's step ids — after renaming a step in code, deploying a changed workflow against old persisted runs, or time-traveling to an unnamed .map() step whose generated id differs between processes.

Common situations: Deploying updated workflow definitions while old runs are replayed; referencing steps by auto-generated ids; renaming/refactoring steps without migrating stored snapshots.

Related errors


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