mastra-ai/mastra · error · MastraError

DURABLE_AGENT_RECOVER_AGENT_MISMATCH

DURABLE_AGENT_RECOVER_AGENT_MISMATCH

Error message

DurableAgent "${this.name}" recover(${runId}): persisted run belongs to agent "${workflowInput.agentId}", not "${this.id}".

What it means

Once the snapshot's durable-agent workflow input is validated, #loadRecoverableWorkflowInput compares workflowInput.agentId with this.id. If the persisted run was created by a different agent, recover() refuses to hijack another agent's run and throws this USER error with the owning agent's ID in details.ownerAgentId.

Source

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

    }

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

    return workflowInput;
  }

  /**
   * Rebuild and register the stream for a claimed recovery attempt. Rolls back
   * every partial registration and releases the claim if setup fails.
   */
  async #setupRecoveredStream({
    runId,
    workflowInput,

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Call recover() on the owning agent — the error's details.ownerAgentId tells you which one.
  2. Fix agent resolution (e.g. mastra.getAgent(ownerAgentId)) in the recovery job.
  3. If the agent's id changed intentionally, migrate or re-attribute old runs, or re-run the tasks under the new agent.
  4. Filter recovery queues by agentId so each agent only recovers its own runs.

Example fix

// before
await agentA.recover(runId); // run belongs to agentB
// after
const run = await workflowsStore.getWorkflowRunById({ runId, workflowName: DurableStepIds.AGENTIC_LOOP });
const input = JSON.parse(String(run.snapshot)).context.input;
const owner = mastra.getAgent(input.agentId);
await owner.recover(runId);
Defensive patterns

Strategy: validation

Validate before calling

const input = getWorkflowInput(runId); // parse snapshot.context.input
if (input?.agentId !== agent.id) {
  throw new Error(`Run ${runId} belongs to agent ${input?.agentId}; use that agent to recover.`);
}

Try / catch

try {
  await agent.recover(runId);
} catch (e) {
  if (String(e?.id) === 'DURABLE_AGENT_RECOVER_AGENT_MISMATCH') {
    const owner = mastra.getAgent(e?.details?.ownerAgentId);
    await owner.recover(runId); // route to owning agent
  } else throw e;
}

Prevention

When it happens

Trigger: Calling recover(runId) on agent A when the runId was produced by agent B — e.g. shared storage across agents, wrong agent instance retrieved from mastra.getAgent(), or agent renamed/re-created with a new id so old runs no longer match this.id.

Common situations: Multiple agents sharing one storage backend and a scheduler recovering failed runs against the wrong agent; renaming an agent (id changes) and then trying to recover its old runs; copy-pasted recovery job not parameterized per agent.

Related errors


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