mastra-ai/mastra · error

Multiple suspended steps found: ${pathStrings.join(', ')}. P

Error message

Multiple suspended steps found: ${pathStrings.join(', ')}. Please specify which step to resume using the "step" parameter.

What it means

Thrown when resume() is called without a step and the snapshot contains more than one suspended step path. The engine refuses to guess which one to continue and lists the paths (including nested paths) in the message.

Source

Thrown at packages/core/src/workflows/workflow.ts:4489

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

    if (!params.retryCount) {
      const suspendedStepIds = Object.keys(snapshot?.suspendedPaths ?? {});

      const isStepSuspended = suspendedStepIds.includes(steps?.[0] ?? '');

      if (!isStepSuspended) {
        throw new Error(
          `This workflow step "${steps?.[0]}" was not suspended. Available suspended steps: [${suspendedStepIds.join(', ')}]`,
        );
      }
    }

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Pass the step parameter naming which suspended step to resume: resume({ resumeData, step: 'stepId' }).
  2. For nested steps, pass the full dotted path or array path, e.g. step: ['parentStep', 'childStep'].
  3. Read the error message — it lists the available suspended paths — or inspect snapshot.suspendedPaths.
  4. Resume each suspended branch with separate resume() calls, one per step.

Example fix

// before
await run.resume({ resumeData });
// after
await run.resume({ resumeData, step: 'approvalBranchA' });
await run.resume({ resumeData, step: 'approvalBranchB' });
Defensive patterns

Strategy: validation

Validate before calling

const snapshot = await run.getWorkflowRunState();
const suspended = Object.keys(snapshot.suspendedPaths ?? {});
if (suspended.length > 1) {
  throw new Error(`Must specify step; suspended: ${suspended.join(', ')}`);
}

Type guard

function hasSingleSuspension(s: { suspendedPaths?: Record<string, unknown> }): boolean {
  return Object.keys(s.suspendedPaths ?? {}).length === 1;
}

Try / catch

try {
  await run.resume({ resumeData });
} catch (e) {
  if (e instanceof Error && e.message.startsWith('Multiple suspended steps found')) {
    // parse listed paths or read suspendedPaths, then resume per-step
  } else throw e;
}

Prevention

When it happens

Trigger: Calling resume({ resumeData }) with no step when the workflow suspended at two or more parallel/concurrent steps, or multiple steps suspended in a foreach; nested workflows suspended in several branches.

Common situations: Parallel branches each with a suspend() call; resuming a human-in-the-loop workflow with several approvals pending; developer added a second suspended step to an existing workflow whose clients still call resume() without step.

Related errors


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