{"record":{"id":"4a45fbbce1f1a7e4","repo":"mastra-ai/mastra","slug":"snapshot-not-found-for-run-this-runid","errorCode":null,"errorMessage":"Snapshot not found for run ${this.runId}","messagePattern":"Snapshot not found for run (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/core/src/workflows/workflow.ts","lineNumber":4719,"sourceCode":"    requestContext?: RequestContext<TRequestContext>;\n    outputWriter?: OutputWriter;\n    tracingOptions?: TracingOptions;\n    actor?: ActorSignal;\n  } & Partial<ObservabilityContext>): Promise<WorkflowResult<TState, TInput, TOutput, TSteps>> {\n    const observabilityContext = resolveObservabilityContext(rest);\n    const allowedEngines = ['default', 'evented'];\n    if (!allowedEngines.includes(this.workflowEngineType)) {\n      throw new Error(`restart() is not supported on ${this.workflowEngineType} workflows`);\n    }\n\n    const workflowsStore = await this.#mastra?.getStorage()?.getStore('workflows');\n    const snapshot = await workflowsStore?.loadWorkflowSnapshot({\n      workflowName: this.workflowId,\n      runId: this.runId,\n    });\n\n    if (!snapshot) {\n      throw new Error(`Snapshot not found for run ${this.runId}`);\n    }\n\n    // Parent parallel activeStepsPath can lag behind nested child completion after a crash:\n    // children may already be terminal while the parent still lists them as active and\n    // re-invokes restart(). Treat terminal snapshots as authoritative and reuse them.\n    // See https://github.com/mastra-ai/mastra/issues/20225\n    //\n    // Only statuses already represented on WorkflowResult are reconstructed here.\n    // Other terminal statuses (canceled/bailed) keep the existing createRestartExecutionParams\n    // \"was not active\" behavior — expanding WorkflowResult is out of scope for this fix.\n    if (snapshot.status === 'success' || snapshot.status === 'failed' || snapshot.status === 'tripwire') {\n      this.cleanup?.();\n      // Match fmtReturnValue: context keeps `input` alongside step results, and `input`\n      // is also surfaced as a top-level field on the returned WorkflowResult.\n      const hydratedSteps = hydrateSerializedStepErrors({ ...(snapshot.context ?? {}) }) ?? {};\n      // Strip internal bookkeeping (__state, metadata.nestedRunId) from step results so the\n      // reconstructed result matches what a live run would have returned via fmtReturnValue.\n      const steps = Object.fromEntries(","sourceCodeStart":4701,"sourceCodeEnd":4737,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/core/src/workflows/workflow.ts#L4701-L4737","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Configure a persistent workflow storage (libsql/pg/upstash/redis) so snapshots survive crashes.","Verify the recovery job reads runIds from the same storage instance the workflow wrote to.","Skip runIds with no snapshot in your recovery loop (they never started or were pruned).","Check for snapshot cleanup/TTL settings that might delete runs you still intend to restart."],"exampleFix":"// before\nawait run.restart();\n// after\nconst snapshot = await storage.loadWorkflowSnapshot({ workflowName: wf.id, runId });\nif (snapshot) await run.restart();\nelse logger.warn(`Skipping ${runId}: no snapshot to restart from`);","handlingStrategy":"validation","validationCode":"const snapshot = await storage.loadWorkflowSnapshot({ workflowName: wf.id, runId });\nif (!snapshot) {\n  logger.warn(`Skipping restart for ${runId}: no snapshot`);\n  return;\n}","typeGuard":"function canRestart(s: unknown): s is { status: string } {\n  return !!s && typeof s === 'object' && 'status' in s;\n}","tryCatchPattern":"try {\n  await run.restart();\n} catch (e) {\n  if (e instanceof Error && e.message.startsWith('Snapshot not found for run')) {\n    // skip in recovery loop; run never persisted or was pruned\n  } else throw e;\n}","preventionTips":["Use persistent storage if you rely on restart() for crash recovery.","Only enqueue runIds for restart after their first snapshot is persisted.","Align snapshot TTL/cleanup with recovery SLAs.","Ensure recovery jobs read the same DB the workflows write to."],"tags":["workflow","restart","storage","snapshot","crash-recovery"],"backgroundTag":"workflow-snapshot-not-found","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T08:17:16.595Z"}