mastra-ai/mastra · error · Error

Resume label "${params.label}" not found. Available labels:

Error message

Resume label "${params.label}" not found. Available labels: [${availableLabels.join(', ')}]

What it means

When resume() is called with a label, the library looks it up in snapshot.resumeLabels (populated by suspend() calls with labels). The label isn't present, so it throws with the list of labels that ARE available to help the caller pick a valid one.

Source

Thrown at packages/core/src/workflows/evented/workflow.ts:2345

      throw new Error('Cannot resume workflow: workflows store is required');
    }
    const snapshot = await waitForSuspendedSnapshot(workflowsStore, this.workflowId, this.runId);
    if (!snapshot) {
      throw new Error(`Cannot resume workflow: no snapshot found for runId ${this.runId}`);
    }

    // Check if workflow is suspended before proceeding
    if (snapshot.status !== 'suspended') {
      throw new Error('This workflow run was not suspended');
    }

    // Resolve label to step path if provided
    const snapshotResumeLabel = params.label ? snapshot?.resumeLabels?.[params.label] : undefined;

    // Validate label exists if provided
    if (params.label && !snapshotResumeLabel) {
      const availableLabels = Object.keys(snapshot?.resumeLabels ?? {});
      throw new Error(
        `Resume label "${params.label}" not found. ` + `Available labels: [${availableLabels.join(', ')}]`,
      );
    }

    // Label takes precedence over step param
    const stepParam = snapshotResumeLabel?.stepId ?? params.step;

    // Auto-detect suspended steps if no step is provided
    let steps: string[];
    if (stepParam) {
      if (typeof stepParam === 'string') {
        steps = stepParam.split('.');
      } else {
        steps = (Array.isArray(stepParam) ? stepParam : [stepParam]).map(step =>
          typeof step === 'string' ? step : step?.id,
        );
      }
    } else {

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Copy the label string exactly from the suspend({ label }) call (check the available labels listed in the error)
  2. Log or inspect snapshot.resumeLabels for the run and resume using one of those keys
  3. Use the step id + resumeData form of resume() instead of a label if labels aren't reliably set

Example fix

// before
await run.resume({ label: 'approve', resumeData: { ok: true } });
// error says available: [approval]
// after
await run.resume({ label: 'approval', resumeData: { ok: true } });
Defensive patterns

Strategy: validation

Validate before calling

const snapshot = await storage.loadWorkflowSnapshot({ workflowId, runId });
const labels = Object.keys(snapshot?.resumeLabels ?? {});
if (label && !labels.includes(label)) {
  throw new Error(`Label ${label} not in available: ${labels.join(', ')}`);
}

Type guard

function hasResumeLabel(s, label) {
  return Boolean(s?.resumeLabels && label in s.resumeLabels);
}

Try / catch

try {
  await run.resume({ runId, label, resumeData });
} catch (e) {
  if (e.message.includes('Resume label')) {
    // parse available labels from message and retry with a valid one, or resume by step
    throw e;
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling resume({ label: 'myLabel', ... }) where snapshot.resumeLabels is undefined, empty, or doesn't contain 'myLabel' — label typo, suspend executed without a label, or resuming against the wrong run whose suspension points differ.

Common situations: Renaming a label in the step's suspend() but not at all resume call sites; resuming a different run than intended (labels differ per run path); label defined only on a branch that wasn't taken.

Related errors


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