mastra-ai/mastra · error · Error

No suspended steps found in this workflow run

Error message

No suspended steps found in this workflow run

What it means

When resume() is called without a step or label, the library inspects the snapshot to enumerate suspended step paths and pick which step(s) to resume. If none of the steps in the snapshot's context are suspended (even though snapshot.status said 'suspended'), there is nothing to target and it throws.

Source

Thrown at packages/core/src/workflows/evented/workflow.ts:2386

        // Check if this step has nested workflow suspension data
        const stepResult = snapshot?.context?.[stepId];
        if (stepResult && typeof stepResult === 'object' && 'status' in stepResult) {
          const stepRes = stepResult as any;
          if (stepRes.status === 'suspended') {
            const nestedPath = stepRes.suspendPayload?.__workflow_meta?.path;
            if (nestedPath && Array.isArray(nestedPath)) {
              // For nested workflows, combine the parent step ID with the nested path
              suspendedStepPaths.push([stepId, ...nestedPath]);
            } else {
              // For single-level suspension, just use the step ID
              suspendedStepPaths.push([stepId]);
            }
          }
        }
      });

      if (suspendedStepPaths.length === 0) {
        throw new Error('No suspended steps found in this workflow run');
      }

      if (suspendedStepPaths.length === 1) {
        // For single suspended step, use the full path
        steps = suspendedStepPaths[0]!;
      } else {
        const pathStrings = suspendedStepPaths.map(path => `[${path.join(', ')}]`);
        throw new Error(
          `Multiple suspended steps found: ${pathStrings.join(', ')}. ` +
            'Please specify which step to resume using the "step" parameter.',
        );
      }
    }

    // Validate that the step is actually suspended
    const suspendedStepIds = Object.keys(snapshot?.suspendedPaths ?? {});
    const isStepSuspended = suspendedStepIds.includes(steps?.[0] ?? '');

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Pass an explicit step (and nested path if needed) to resume: run.resume({ runId, step: myStep, resumeData })
  2. Use a suspend label so resume doesn't need to infer the step
  3. Re-run the workflow if the snapshot is corrupt; verify storage contents for context.status === 'suspended' entries

Example fix

// before
await run.resume({ runId, resumeData }); // no step, none inferred
// after
await run.resume({ runId, step: approvalStep, resumeData });
Defensive patterns

Strategy: fallback

Validate before calling

const snapshot = await storage.loadWorkflowSnapshot({ workflowId, runId });
const hasSuspendedSteps = Object.values(snapshot?.context?.steps ?? {}).some(
  (s) => s?.status === 'suspended',
);
if (!hasSuspendedSteps) throw new Error('No suspended steps to resume; pass an explicit step or restart the run');

Type guard

null

Try / catch

try {
  await run.resume({ runId, resumeData });
} catch (e) {
  if (e.message.includes('No suspended steps found')) {
    // fall back to explicit step resume or start a new run
    await run.resume({ runId, step: approvalStep, resumeData });
  } else throw e;
}

Prevention

When it happens

Trigger: Calling resume() with neither step nor label on a snapshot whose status is 'suspended' but whose suspended step bookkeeping is empty — e.g. a nested/parallel flow where suspension state was recorded at the top level but per-step paths weren't persisted, or a corrupted/hand-edited snapshot.

Common situations: Migrated snapshots from older versions lacking the suspended-step structure; resuming runs created by nested workflows where the inner step holds the suspension; custom storage writes that dropped context.status data.

Related errors


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