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
- Fetch the persisted run state (workflows store getWorkflowRunById) and only call resume when status === 'suspended'.
- If the run already completed, read its result instead of resuming.
- Deduplicate resume calls (disable the UI action / idempotency key) so only one resume is issued per suspension.
- 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
- Check run status before resuming (idempotent resume guard).
- Disable resume UI while a resume request is in flight.
- Use a single owner/job to issue resumes per run.
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
- No registry entry found for run ${runId}. Cannot resume.
- DURABLE_AGENT_RESUME_AGENT_MISMATCH
- Failed to rehydrate registry entry for run ${runId}. Cannot
- ClaudeSDKAgent resumeData must include sessionId or continue
- CursorSDKAgent resumeData must include a message.
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/b89d3d68bc2cb0a1.
Report an issue: GitHub.