mastra-ai/mastra · error

Snapshot not found for run ${this.runId}

Error message

Snapshot not found for run ${this.runId}

What it means

Thrown by restart() when loadWorkflowSnapshot() returns no snapshot for the runId — the persisted state needed to re-drive the run cannot be found, so there is nothing to restart from.

Source

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

    requestContext?: RequestContext<TRequestContext>;
    outputWriter?: OutputWriter;
    tracingOptions?: TracingOptions;
    actor?: ActorSignal;
  } & Partial<ObservabilityContext>): Promise<WorkflowResult<TState, TInput, TOutput, TSteps>> {
    const observabilityContext = resolveObservabilityContext(rest);
    const allowedEngines = ['default', 'evented'];
    if (!allowedEngines.includes(this.workflowEngineType)) {
      throw new Error(`restart() is not supported on ${this.workflowEngineType} workflows`);
    }

    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}`);
    }

    // Parent parallel activeStepsPath can lag behind nested child completion after a crash:
    // children may already be terminal while the parent still lists them as active and
    // re-invokes restart(). Treat terminal snapshots as authoritative and reuse them.
    // See https://github.com/mastra-ai/mastra/issues/20225
    //
    // Only statuses already represented on WorkflowResult are reconstructed here.
    // Other terminal statuses (canceled/bailed) keep the existing createRestartExecutionParams
    // "was not active" behavior — expanding WorkflowResult is out of scope for this fix.
    if (snapshot.status === 'success' || snapshot.status === 'failed' || snapshot.status === 'tripwire') {
      this.cleanup?.();
      // Match fmtReturnValue: context keeps `input` alongside step results, and `input`
      // is also surfaced as a top-level field on the returned WorkflowResult.
      const hydratedSteps = hydrateSerializedStepErrors({ ...(snapshot.context ?? {}) }) ?? {};
      // Strip internal bookkeeping (__state, metadata.nestedRunId) from step results so the
      // reconstructed result matches what a live run would have returned via fmtReturnValue.
      const steps = Object.fromEntries(

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Configure a persistent workflow storage (libsql/pg/upstash/redis) so snapshots survive crashes.
  2. Verify the recovery job reads runIds from the same storage instance the workflow wrote to.
  3. Skip runIds with no snapshot in your recovery loop (they never started or were pruned).
  4. Check for snapshot cleanup/TTL settings that might delete runs you still intend to restart.

Example fix

// before
await run.restart();
// after
const snapshot = await storage.loadWorkflowSnapshot({ workflowName: wf.id, runId });
if (snapshot) await run.restart();
else logger.warn(`Skipping ${runId}: no snapshot to restart from`);
Defensive patterns

Strategy: validation

Validate before calling

const snapshot = await storage.loadWorkflowSnapshot({ workflowName: wf.id, runId });
if (!snapshot) {
  logger.warn(`Skipping restart for ${runId}: no snapshot`);
  return;
}

Type guard

function canRestart(s: unknown): s is { status: string } {
  return !!s && typeof s === 'object' && 'status' in s;
}

Try / catch

try {
  await run.restart();
} catch (e) {
  if (e instanceof Error && e.message.startsWith('Snapshot not found for run')) {
    // skip in recovery loop; run never persisted or was pruned
  } else throw e;
}

Prevention

When it happens

Trigger: Calling restart() with a runId that has no snapshot: run never started, snapshot deleted, storage not shared across processes, or crash happened before the first snapshot was written.

Common situations: Recovery job replaying runIds after a redeploy that switched databases; in-memory storage lost on crash (which is exactly when restart is wanted — needs a persistent store); runIds from a different environment; snapshot pruning policies removing old runs.

Related errors


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