mastra-ai/mastra · error · HTTPException

runId required to time travel workflow

Error message

runId required to time travel workflow

What it means

POST /workflows/:workflowId/time-travel-async returns 400 with this message when the runId query parameter is missing. Time travel always operates on an existing run, so the handler rejects requests without runId before doing any lookup.

Source

Thrown at packages/server/src/server/handlers/workflows.ts:1157

  responseType: 'json',
  pathParamSchema: workflowIdPathParams,
  queryParamSchema: runIdSchema,
  bodySchema: timeTravelBodySchema,
  responseSchema: workflowExecutionResultSchema,
  summary: 'Time travel workflow asynchronously',
  description: 'Time travels a workflow run asynchronously without streaming',
  tags: ['Workflows'],
  requiresAuth: true,
  handler: async ({ mastra, workflowId, runId, requestContext, ...params }) => {
    try {
      const effectiveResourceId = getEffectiveResourceId(requestContext, undefined);

      if (!workflowId) {
        throw new HTTPException(400, { message: 'Workflow ID is required' });
      }

      if (!runId) {
        throw new HTTPException(400, { message: 'runId required to time travel workflow' });
      }

      const { workflow } = await listWorkflowsFromSystem({ mastra, workflowId });

      if (!workflow) {
        throw new HTTPException(404, { message: 'Workflow not found' });
      }

      const run = await workflow.getWorkflowRunById(runId);

      if (!run) {
        throw new HTTPException(404, { message: 'Workflow run not found' });
      }

      await validateRunOwnership(run, effectiveResourceId);

      const _run = await workflow.createRun({ runId, resourceId: run.resourceId });
      const result = await _run.timeTravel({ ...params, requestContext });

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Append ?runId=<runId> to the request URL
  2. Verify the runId value is defined and non-empty before issuing the request
  3. Use the run id returned by workflow.createRun() or from the stored run, not the workflow id

Example fix

// before
await fetch(`/api/workflows/${workflowId}/time-travel-async`, { method: 'POST', body });
// after
await fetch(`/api/workflows/${workflowId}/time-travel-async?runId=${runId}`, { method: 'POST', body });
Defensive patterns

Strategy: validation

Validate before calling

if (!runId) throw new Error('runId is required');
const url = `/api/workflows/${workflowId}/time-travel-async?runId=${encodeURIComponent(runId)}`;

Type guard

function hasRunId(v: unknown): v is string {
  return typeof v === 'string' && v.length > 0;
}

Try / catch

try {
  return await timeTravelAsync(workflowId, runId);
} catch (e) {
  if (isHttpError(e) && e.status === 400 && /runId required/.test(e.message)) {
    console.error('Missing runId query param:', { workflowId, runId });
  }
  throw e;
}

Prevention

When it happens

Trigger: POST /workflows/:workflowId/time-travel-async without the ?runId= query param (runIdSchema query param absent, null, or empty string).

Common situations: Forgetting the query param while testing with curl/Postman; client code passes runId in the body instead of the query string; runId variable undefined at call time.

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/09ae381f7fba9e57. Report an issue: GitHub.