mastra-ai/mastra · error · Error

Cannot resume task in status '${task.status}' (expected 'sus

Error message

Cannot resume task in status '${task.status}' (expected 'suspended')

What it means

BackgroundTaskManager.resume() only works on tasks currently in the 'suspended' state. The manager fetches the task record from storage and throws if its status is anything else (running, completed, failed, cancelled, etc.). This guard prevents resuming tasks that are not paused at a suspension point.

Source

Thrown at packages/core/src/background-tasks/manager.ts:428

   * resumed run.
   */
  async resume(taskId: string, resumeData?: unknown): Promise<BackgroundTask> {
    if (this.shuttingDown) {
      throw new Error('BackgroundTaskManager is shutting down, cannot resume tasks');
    }
    if (!this.#mastra) {
      throw new Error('Mastra is not registered with this manager');
    }

    if (this.initPromise) await this.initPromise;

    const storage = await this.getStorage();
    const task = await storage.getTask(taskId);
    if (!task) {
      throw new Error(`Task not found: ${taskId}`);
    }
    if (task.status !== 'suspended') {
      throw new Error(`Cannot resume task in status '${task.status}' (expected 'suspended')`);
    }

    const canRun = await this.checkConcurrency(task.agentId);
    if (!canRun) {
      // Resume sits outside the queue/fallback-sync paths — there's no
      // synchronous caller to fall back to, and silently leaving the task
      // suspended hides the failure from the caller. Throw and let the
      // caller retry once a slot frees.
      throw new Error(`Concurrency limit reached, cannot resume task "${taskId}" — retry once a slot is available`);
    }

    // Resume publishes directly (not via dispatch()), so it needs its own
    // lazy worker start for the library-mode process-restart case.
    await this.#ensureExecutionWorkersStarted();

    // Hand off to the worker subscriber. `task.resume` rides the same
    // `TOPIC_DISPATCH` + `WORKER_GROUP` exactly-once channel as
    // `task.dispatch`, so any worker (including a different process from

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Check the task's current status via storage/manager before calling resume and only resume tasks with status 'suspended'.
  2. If resuming from a UI, disable the resume control after the first click and refresh the task state from the server.
  3. If the task is completed/failed and you want it to run again, use restart() instead of resume().

Example fix

// before
await manager.resume(taskId); // throws if status isn't 'suspended'
// after
const task = await manager.getTask(taskId);
if (task?.status === 'suspended') {
  await manager.resume(taskId);
}
Defensive patterns

Strategy: validation

Validate before calling

async function canResume(manager, taskId) {
  const task = await manager.getTask(taskId);
  return task?.status === 'suspended';
}
// call site:
if (await canResume(manager, taskId)) await manager.resume(taskId);

Type guard

function isSuspended(task) {
  return !!task && task.status === 'suspended';
}

Try / catch

try {
  await manager.resume(taskId);
} catch (e) {
  if (/Cannot resume task in status '(.+)'/.test(e.message)) {
    const status = e.message.match(/Cannot resume task in status '(.+)'/)?.[1];
    logger.warn(`Skipping resume: task is ${status}`);
  } else throw e;
}

Prevention

When it happens

Trigger: Calling manager.resume(taskId) on a task whose stored status is not 'suspended' — e.g. the task already finished, failed, was cancelled, or is still actively running. Also happens when resuming the same task twice concurrently.

Common situations: Double-clicking a 'Resume' button in a UI so resume fires twice; retrying a resume call after a first resume already flipped the task to 'running'; attempting to resume a completed/failed task from a stale task list.

Related errors


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