mastra-ai/mastra · error · Error

BackgroundTaskManager is shutting down, cannot enqueue new t

Error message

BackgroundTaskManager is shutting down, cannot enqueue new tasks

What it means

enqueue() rejects new work when the manager is shutting down. During shutdown the pubsub subscriptions and workers are being torn down, so a newly enqueued task would never be dispatched. The library fails fast rather than silently dropping the task.

Source

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

  /**
   * Look up an executor by tool name. Read by the workflow-step body in
   * `workflow.ts:runAttemptStep` as a fallback when no per-task `TaskContext`
   * is registered (cross-process path).
   */
  getStaticExecutor(toolName: string): ToolExecutor | undefined {
    return this.staticExecutors.get(toolName);
  }

  // --- Core operations ---

  /**
   * Enqueue a task for background execution.
   * Prefer `createBackgroundTask()` which returns a self-contained handle.
   */
  async enqueue(payload: TaskPayload, context?: TaskContext): Promise<EnqueueResult> {
    if (this.shuttingDown) {
      throw new Error('BackgroundTaskManager is shutting down, cannot enqueue new tasks');
    }

    // Mastra fires `init` as fire-and-forget. If a caller hits enqueue
    // before init completes, the dispatch publish fires before the worker
    // subscribes and the event is dropped (or, worse, lands on a worker
    // whose Mastra hasn't yet registered the bg-task workflow → "Workflow
    // with id __background-task not found"). Await readiness up front.
    if (this.initPromise) await this.initPromise;

    const task: BackgroundTask = {
      id: this.#mastra?.generateId() ?? randomUUID(),
      status: 'pending',
      toolName: payload.toolName,
      toolCallId: payload.toolCallId,
      args: payload.args,
      agentId: payload.agentId,
      threadId: payload.threadId,
      resourceId: payload.resourceId,

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Check manager.shuttingDown before enqueueing and fall back to synchronous tool execution.
  2. Add readiness gating: stop accepting requests (return 503) before calling shutdown().
  3. Retry after redeploy/restart, or persist the task externally and enqueue post-restart.
  4. Await in-flight createBackgroundTask dispatches in your shutdown handler before tearing down.

Example fix

// before
await manager.shutdown();
await manager.enqueue(payload); // throws
// after
if (!manager.shuttingDown) {
  await manager.enqueue(payload);
} else {
  const result = await tool.execute(payload); // fallback sync
}
Defensive patterns

Strategy: fallback

Validate before calling

if (manager.shuttingDown) {
  return syncExecuteTask(task); // run inline instead of enqueueing
}

Try / catch

try {
  return await manager.enqueue(payload);
} catch (e) {
  if ((e as Error).message.includes('shutting down, cannot enqueue')) {
    return tool.execute(payload); // fallback to sync
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling manager.enqueue() (directly or via createBackgroundTask) after shutdown() started; a task tool executing concurrently with process shutdown; graceful-drain logic overlapping with new agent/tool calls.

Common situations: Load balancer still routing requests during SIGTERM drain; long-running agent loops scheduling background tasks while the server deploys; dev hot reloads triggering shutdown while a request is in flight.

Related errors


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