{"record":{"id":"49d6a98c4d2747af","repo":"mastra-ai/mastra","slug":"step-is-required-and-must-be-a-valid-step-or-array","errorCode":null,"errorMessage":"Step is required and must be a valid step or array of steps","messagePattern":"Step is required and must be a valid step or array of steps","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/core/src/workflows/workflow.ts","lineNumber":4868,"sourceCode":"          Step<string, any, TInput, any, any, any, TEngineType, any>,\n        ]\n      | string\n      | string[];\n    context?: TimeTravelContext<any, any, any, any>;\n    nestedStepsContext?: Record<string, TimeTravelContext<any, any, any, any>>;\n    requestContext?: RequestContext<TRequestContext>;\n    outputWriter?: OutputWriter;\n    tracingOptions?: TracingOptions;\n    outputOptions?: {\n      includeState?: boolean;\n      includeResumeLabels?: boolean;\n    };\n    perStep?: boolean;\n    actor?: ActorSignal;\n  } & Partial<ObservabilityContext>): Promise<WorkflowResult<TState, TInput, TOutput, TSteps>> {\n    const observabilityContext = resolveObservabilityContext(rest);\n    if (!stepParam || (Array.isArray(stepParam) && stepParam.length === 0)) {\n      throw new Error('Step is required and must be a valid step or array of steps');\n    }\n\n    const workflowsStore = await this.#mastra?.getStorage()?.getStore('workflows');\n    const snapshot = await workflowsStore?.loadWorkflowSnapshot({\n      workflowName: this.workflowId,\n      runId: this.runId,\n    });\n\n    if (!snapshot) {\n      throw new Error(`Snapshot not found for run ${this.runId}`);\n    }\n\n    if (snapshot.status === 'running') {\n      throw new Error('This workflow run is still running, cannot time travel');\n    }\n\n    let steps: string[];\n    let newStepParam = stepParam;","sourceCodeStart":4850,"sourceCodeEnd":4886,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/core/src/workflows/workflow.ts#L4850-L4886","documentation":"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.","triggerScenarios":"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.","commonSituations":"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().","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)."],"exampleFix":"// before\nconst step = suspendedSteps[0]; // may be undefined\nawait run.resume({ resumeData, step });\n// after\nconst step = suspendedSteps[0];\nif (!step) throw new Error('No suspended step available to resume');\nawait run.resume({ resumeData, step });","handlingStrategy":"validation","validationCode":"if (!stepParam || (Array.isArray(stepParam) && stepParam.length === 0)) {\n  throw new Error('step is required and must be a non-empty step or array');\n}","typeGuard":"function isValidStepParam(p: unknown): p is string | { id: string } | (string | { id: string })[] {\n  if (typeof p === 'string') return p.length > 0;\n  if (Array.isArray(p)) return p.length > 0 && p.every(x => typeof x === 'string' || (x && typeof x === 'object' && 'id' in x));\n  return !!p && typeof p === 'object' && 'id' in p;\n}","tryCatchPattern":"try {\n  await run.resume({ resumeData, step });\n} catch (e) {\n  if (e instanceof Error && e.message === 'Step is required and must be a valid step or array of steps') {\n    // validate caller input and retry with a concrete step\n  } else throw e;\n}","preventionTips":["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."],"tags":["workflow","resume","validation","missing-parameter"],"backgroundTag":"missing-required-parameter","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}