mastra-ai/mastra · error

Step is required and must be a valid step or array of steps

Error message

Step is required and must be a valid step or array of steps

What it means

Thrown by the step-targeted resume/recovery API when stepParam is undefined or an empty array. A step (or non-empty step array) is mandatory for this operation — the engine will not infer which step to act on.

Source

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

          Step<string, any, TInput, any, any, any, TEngineType, any>,
        ]
      | string
      | string[];
    context?: TimeTravelContext<any, any, any, any>;
    nestedStepsContext?: Record<string, TimeTravelContext<any, any, any, any>>;
    requestContext?: RequestContext<TRequestContext>;
    outputWriter?: OutputWriter;
    tracingOptions?: TracingOptions;
    outputOptions?: {
      includeState?: boolean;
      includeResumeLabels?: boolean;
    };
    perStep?: boolean;
    actor?: ActorSignal;
  } & Partial<ObservabilityContext>): Promise<WorkflowResult<TState, TInput, TOutput, TSteps>> {
    const observabilityContext = resolveObservabilityContext(rest);
    if (!stepParam || (Array.isArray(stepParam) && stepParam.length === 0)) {
      throw new Error('Step is required and must be a valid step or array of steps');
    }

    const workflowsStore = await this.#mastra?.getStorage()?.getStore('workflows');
    const snapshot = await workflowsStore?.loadWorkflowSnapshot({
      workflowName: this.workflowId,
      runId: this.runId,
    });

    if (!snapshot) {
      throw new Error(`Snapshot not found for run ${this.runId}`);
    }

    if (snapshot.status === 'running') {
      throw new Error('This workflow run is still running, cannot time travel');
    }

    let steps: string[];
    let newStepParam = stepParam;

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Pass a concrete step: step: 'stepId' (or the Step object), or a non-empty array for nested paths.
  2. Validate/whitelist the step value in your server handler before forwarding to resume().
  3. When resuming by label, ensure the label exists in snapshot.resumeLabels so stepId resolves.
  4. Fix upstream code that produces empty arrays (e.g. suspendedSteps[0] on an empty list).

Example fix

// before
const step = suspendedSteps[0]; // may be undefined
await run.resume({ resumeData, step });
// after
const step = suspendedSteps[0];
if (!step) throw new Error('No suspended step available to resume');
await run.resume({ resumeData, step });
Defensive patterns

Strategy: validation

Validate before calling

if (!stepParam || (Array.isArray(stepParam) && stepParam.length === 0)) {
  throw new Error('step is required and must be a non-empty step or array');
}

Type guard

function isValidStepParam(p: unknown): p is string | { id: string } | (string | { id: string })[] {
  if (typeof p === 'string') return p.length > 0;
  if (Array.isArray(p)) return p.length > 0 && p.every(x => typeof x === 'string' || (x && typeof x === 'object' && 'id' in x));
  return !!p && typeof p === 'object' && 'id' in p;
}

Try / catch

try {
  await run.resume({ resumeData, step });
} catch (e) {
  if (e instanceof Error && e.message === 'Step is required and must be a valid step or array of steps') {
    // validate caller input and retry with a concrete step
  } else throw e;
}

Prevention

When it happens

Trigger: Calling resume/retry with step: undefined, step: [], or a params object where the label-based stepId lookup returned undefined and no explicit step was given; an empty array produced by filtering step lists.

Common situations: Spreading a possibly-empty array of step ids into options; variable holding the step id never assigned; client sends a payload without the step field through a server handler that forwards it directly to resume().

Understand the failure class

Background: Missing required parameter errors: what 'X is required' and 'the required X param is missing' mean, and how to fix them — this error's family across 27 libraries.

Related errors


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