mastra-ai/mastra · error · MastraError

DURABLE_AGENT_RECOVER_NO_STORAGE

DURABLE_AGENT_RECOVER_NO_STORAGE

Error message

DurableAgent "${this.name}" recover() requires persistent storage to load the run snapshot. Register the agent on a Mastra instance with persistent storage (e.g. PostgreSQL, LibSQL).

What it means

recover() must load the run snapshot from persistent storage via mastra.getStorage()?.getStore('workflows'). If no storage is configured (or the storage exposes no workflows store), MastraError DURABLE_AGENT_RECOVER_NO_STORAGE is thrown, advising persistent storage such as PostgreSQL or LibSQL.

Source

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

   * ```
   */
  async recover(
    runId: string,
    options?: DurableAgentRecoverOptions<TOutput>,
  ): Promise<DurableAgentStreamResult<TOutput>> {
    if (!this.#mastra) {
      throw new MastraError({
        id: 'DURABLE_AGENT_RECOVER_NO_MASTRA',
        domain: ErrorDomain.AGENT,
        category: ErrorCategory.USER,
        text: `DurableAgent "${this.name}" recover() requires the agent to be registered on a Mastra instance.`,
        details: { agentName: this.name, runId },
      });
    }

    const workflowsStore = await this.#mastra.getStorage()?.getStore('workflows');
    if (!workflowsStore) {
      throw new MastraError({
        id: 'DURABLE_AGENT_RECOVER_NO_STORAGE',
        domain: ErrorDomain.AGENT,
        category: ErrorCategory.USER,
        text:
          `DurableAgent "${this.name}" recover() requires persistent storage to load the run snapshot. ` +
          `Register the agent on a Mastra instance with persistent storage (e.g. PostgreSQL, LibSQL).`,
        details: { agentName: this.name, runId },
      });
    }

    // 1. Validate the persisted durable-agent input before claiming ownership
    //    so obvious caller errors fail fast.
    let workflowInput = await this.#loadRecoverableWorkflowInput(workflowsStore, runId);

    // 2. Claim recovery ownership before resolving any live dependencies so a
    //    concurrent caller cannot finish first and leave this attempt using a
    //    stale snapshot.
    const abortController = new AbortController();

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Configure persistent storage: new Mastra({ storage: new PostgresStore({ ... }) }) (or LibSQL/Upstash etc.).
  2. Verify getStorage() returns an instance and that the same storage was used when the run was created.
  3. Check the storage connection config (DATABASE_URL etc.) — a failed adapter init can leave storage undefined.
  4. For tests, use a file-backed or persistent-compatible store rather than pure in-memory.

Example fix

// before
const mastra = new Mastra({ agents: { helper: agent } });
await mastra.getAgent('helper').recover(runId); // throws
// after
const mastra = new Mastra({ agents: { helper: agent }, storage: new PostgresStore({ connectionString: process.env.DATABASE_URL }) });
await mastra.getAgent('helper').recover(runId);
Defensive patterns

Strategy: validation

Validate before calling

if (!mastra.getStorage()?.getStore('workflows')) {
  throw new Error('Durable agent recovery requires persistent storage');
}

Try / catch

try {
  await agent.recover(runId);
} catch (e) {
  if ((e as any).id === 'DURABLE_AGENT_RECOVER_NO_STORAGE') {
    // configure storage before retrying
  } else throw e;
}

Prevention

When it happens

Trigger: Creating a Mastra instance without the storage option and calling recover(); configuring storage that doesn't implement the workflows store; passing an in-memory/volatile storage where the snapshot has already been evicted so the store lookup fails.

Common situations: Dev environments defaulting to no storage while production uses Postgres; misconfigured DATABASE_URL so the storage adapter never initializes; swapping storage backends between runs of the app.

Related errors


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