mastra-ai/mastra · error · Error

This workflow run was not suspended

Error message

This workflow run was not suspended

What it means

DurableAgent resume only supports runs whose persisted workflow snapshot has status 'suspended'. If the stored snapshot shows the run is running, completed, failed, or in another state, resuming is meaningless and this Error is thrown from durable-agent.ts:1950.

Source

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

      // A persisted durable run can outlive this process (or the registry TTL).
      // Rebuild the non-serializable runtime state before resuming the stored
      // workflow snapshot. Keep warm resumes on the existing path to avoid
      // racing an active registry entry with a second preparation pass.
      const workflowsStore = await this.#mastra?.getStorage()?.getStore('workflows');
      const persisted = await workflowsStore?.getWorkflowRunById({
        runId,
        workflowName: DurableStepIds.AGENTIC_LOOP,
      });
      if (!persisted) {
        throw new Error(`No registry entry found for run ${runId}. Cannot resume.`);
      }

      const snapshot =
        typeof persisted.snapshot === 'string'
          ? (JSON.parse(persisted.snapshot) as WorkflowRunState)
          : persisted.snapshot;
      if (snapshot?.status !== 'suspended') {
        throw new Error('This workflow run was not suspended');
      }
      const workflowInput = snapshot?.context?.input as DurableAgenticWorkflowInput | undefined;
      if (!workflowInput || workflowInput.__workflowKind !== 'durable-agent') {
        throw new MastraError({
          id: 'DURABLE_AGENT_RESUME_INVALID_SNAPSHOT',
          domain: ErrorDomain.AGENT,
          category: ErrorCategory.SYSTEM,
          text: `DurableAgent "${this.name}" resume(${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_RESUME_AGENT_MISMATCH',
          domain: ErrorDomain.AGENT,
          category: ErrorCategory.USER,
          text: `DurableAgent "${this.name}" resume(${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. Fetch the persisted run state (workflows store getWorkflowRunById) and only call resume when status === 'suspended'.
  2. If the run already completed, read its result instead of resuming.
  3. Deduplicate resume calls (disable the UI action / idempotency key) so only one resume is issued per suspension.
  4. If the run is stuck in 'running' after a crash, use recover() instead of resume().

Example fix

// before
await agent.resume(runId, data);
// after
const run = await mastra.getStorage()?.getStore('workflows')?.getWorkflowRunById({ runId, workflowName: 'agentic-loop' });
const status = typeof run?.snapshot === 'string' ? JSON.parse(run.snapshot).status : run?.snapshot?.status;
if (status === 'suspended') await agent.resume(runId, data);
Defensive patterns

Strategy: validation

Validate before calling

const run = await mastra.getStorage()?.getStore('workflows')?.getWorkflowRunById({ runId, workflowName: 'agentic-loop' });
const snap = typeof run?.snapshot === 'string' ? JSON.parse(run.snapshot) : run?.snapshot;
if (snap?.status !== 'suspended') return; // skip resume

Type guard

function isSuspended(snapshot: unknown): snapshot is { status: 'suspended' } {
  return typeof snapshot === 'object' && snapshot !== null && (snapshot as any).status === 'suspended';
}

Try / catch

try {
  await agent.resume(runId, data);
} catch (e) {
  if (String(e) === 'This workflow run was not suspended') {
    // already running/finished: fetch result or ignore duplicate resume
  } else throw e;
}

Prevention

When it happens

Trigger: Calling resume(runId, data) on a run that already completed or failed; calling resume concurrently while the workflow is actively executing; resuming a run that was never suspended at the human-in-the-loop step; calling resume twice with the same resumeData (second call sees a running/completed run).

Common situations: Double-submitting a resume from a UI button without disabling it; a background job already resumed the run before the user interaction; retry logic firing after the run reached terminal state; resuming after a crash where the run actually kept going.

Related errors


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