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
- Pass a concrete step: step: 'stepId' (or the Step object), or a non-empty array for nested paths.
- Validate/whitelist the step value in your server handler before forwarding to resume().
- When resuming by label, ensure the label exists in snapshot.resumeLabels so stepId resolves.
- 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
- Validate the step field in API/server handlers before calling resume().
- Guard against empty arrays from filtered step lists.
- Prefer passing Step objects over strings for type safety.
- Resolve labels to stepIds and check they exist before resuming.
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
- This workflow step "${steps?.[0]}" was not suspended. Availa
- This workflow step "${steps?.[0]}" was not suspended. Availa
- runId required to time travel workflow stream
- runId required to cancel workflow run
- ClaudeSDKAgent resumeData must include sessionId or continue
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/49d6a98c4d2747af.
Report an issue: GitHub.