mastra-ai/mastra · error · MastraError

DURABLE_AGENT_RECOVER_INVALID_SNAPSHOT

DURABLE_AGENT_RECOVER_INVALID_SNAPSHOT

Error message

DurableAgent "${this.name}" recover(${runId}): persisted snapshot does not contain a durable-agent workflow input.

What it means

After loading a persisted run, #loadRecoverableWorkflowInput parses the snapshot and reads snapshot.context.input, requiring it to exist and carry __workflowKind === 'durable-agent'. If the snapshot lacks a durable-agent workflow input, the stored run is not a durable-agent run (or is corrupt), and recover() throws this SYSTEM-category error.

Source

Thrown at packages/core/src/agent/durable/durable-agent.ts:723

    if (!persisted) {
      throw new MastraError({
        id: 'DURABLE_AGENT_RECOVER_SNAPSHOT_NOT_FOUND',
        domain: ErrorDomain.AGENT,
        category: ErrorCategory.USER,
        text:
          `DurableAgent "${this.name}" recover(${runId}): no persisted workflow snapshot found. ` +
          `The run may have already completed or been cleaned up.`,
        details: { agentName: this.name, runId },
      });
    }

    const snapshot =
      typeof persisted.snapshot === 'string'
        ? (JSON.parse(persisted.snapshot) as WorkflowRunState)
        : persisted.snapshot;
    const workflowInput = snapshot?.context?.input as DurableAgenticWorkflowInput | undefined;
    if (!workflowInput || workflowInput.__workflowKind !== 'durable-agent') {
      throw new MastraError({
        id: 'DURABLE_AGENT_RECOVER_INVALID_SNAPSHOT',
        domain: ErrorDomain.AGENT,
        category: ErrorCategory.SYSTEM,
        text: `DurableAgent "${this.name}" recover(${runId}): persisted snapshot does not contain a durable-agent workflow input.`,
        details: { agentName: this.name, runId },
      });
    }

    if (workflowInput.agentId !== this.id) {
      throw new MastraError({
        id: 'DURABLE_AGENT_RECOVER_AGENT_MISMATCH',
        domain: ErrorDomain.AGENT,
        category: ErrorCategory.USER,
        text: `DurableAgent "${this.name}" recover(${runId}): persisted run belongs to agent "${workflowInput.agentId}", not "${this.id}".`,
        details: { agentName: this.name, runId, ownerAgentId: workflowInput.agentId },
      });
    }

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Verify the runId refers to a durable-agent run (created by this agent's AGENTIC_LOOP), not a plain workflow run.
  2. Inspect the persisted snapshot: confirm snapshot.context.input.__workflowKind === 'durable-agent'.
  3. If the run predates the current schema (version mismatch), re-run the task instead of recovering the old-format run.
  4. If the snapshot JSON is corrupt, restore from a storage backup or discard the run.

Example fix

// before
await agent.recover(workflowRunId); // actually a plain workflow run
// after
const run = await workflowsStore.getWorkflowRunById({ runId: workflowRunId, workflowName: DurableStepIds.AGENTIC_LOOP });
const snap = typeof run?.snapshot === 'string' ? JSON.parse(run.snapshot) : run?.snapshot;
if (snap?.context?.input?.__workflowKind === 'durable-agent') {
  await agent.recover(workflowRunId);
}
Defensive patterns

Strategy: type-guard

Validate before calling

const run = await workflowsStore.getWorkflowRunById({ runId, workflowName: DurableStepIds.AGENTIC_LOOP });
const snap = typeof run?.snapshot === 'string' ? JSON.parse(run.snapshot) : run?.snapshot;
const input = snap?.context?.input;
if (input?.__workflowKind !== 'durable-agent') throw new Error(`Run ${runId} is not a durable-agent run.`);

Type guard

function isDurableAgentSnapshot(snap: unknown): boolean {
  const input = (snap as any)?.context?.input;
  return !!input && input.__workflowKind === 'durable-agent';
}

Try / catch

try {
  await agent.recover(runId);
} catch (e) {
  if (String(e?.id) === 'DURABLE_AGENT_RECOVER_INVALID_SNAPSHOT') {
    // old-schema or non-durable run: re-run the task instead of recovering
    await restartOriginalTask(runId);
  } else throw e;
}

Prevention

When it happens

Trigger: Calling agent.recover(runId) on a run whose snapshot (a) has no context.input, (b) has input without __workflowKind 'durable-agent' — e.g. the runId belongs to a plain workflow run, or the snapshot was written by an older/incompatible version or corrupted (truncated JSON).

Common situations: Passing a regular workflow runId (or another agent's run kind) to recover(); upgrading Mastra where snapshot schema changed and old runs no longer match; corrupted rows from a failed write or manual storage migration.

Related errors


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