mastra-ai/mastra · error · Error

Task has not been dispatched yet

Error message

Task has not been dispatched yet

What it means

Thrown by the synchronous `task` getter of a BackgroundTaskHandle when the handle has not been dispatched. The handle stores the task ID in a closure variable that is only set inside `dispatch()`; reading `handle.task` before dispatching means no ID exists yet, so the getter throws instead of returning a bogus task object.

Source

Thrown at packages/core/src/background-tasks/create.ts:44

 *     onResult: (params) => messageList.addToolResult(params),
 *   },
 * });
 *
 * const { task, fallbackToSync } = await bgTask.dispatch();
 * const completed = await bgTask.waitForCompletion();
 * await bgTask.cancel();
 * ```
 */
export function createBackgroundTask(
  manager: BackgroundTaskManager,
  options: CreateBackgroundTaskOptions,
): BackgroundTaskHandle {
  const { context, ...payload } = options;
  let taskId: string | undefined;

  return {
    get task() {
      if (!taskId) throw new Error('Task has not been dispatched yet');
      // Synchronous access to task ID — full task data requires async getTask()
      return { id: taskId } as any;
    },

    async dispatch() {
      const result = await manager.enqueue(payload, context);
      taskId = result.task.id;
      return result;
    },

    async checkIfSuspended(args: CheckIfSuspendedPayload) {
      const result = await manager.listTasks({
        toolCallId: args.toolCallId,
        runId: args.runId,
        agentId: args.agentId,
        threadId: args.threadId,
        resourceId: args.resourceId,
        toolName: args.toolName,

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Call `await handle.dispatch()` before reading `handle.task`.
  2. If you need the ID without dispatching, restructure to dispatch first and then use the returned ID.
  3. Track the dispatched ID yourself from `dispatch()`'s result and pass it where needed instead of reading the sync getter.

Example fix

// before
const handle = createBackgroundTask(options);
console.log(handle.task.id); // throws

// after
const handle = createBackgroundTask(options);
await handle.dispatch();
console.log(handle.task.id);
Defensive patterns

Strategy: try-catch

Validate before calling

// before reading the sync getter
let dispatched = false;
const handle = createBackgroundTask(options);
await handle.dispatch();
dispatched = true;
if (dispatched) console.log(handle.task.id);

Type guard

function isDispatched(handle: { task?: { id: string } }): boolean {
  try {
    return typeof handle.task?.id === 'string';
  } catch {
    return false;
  }
}

Try / catch

let taskId: string | undefined;
try {
  taskId = handle.task.id;
} catch (err) {
  if (err instanceof Error && err.message === 'Task has not been dispatched yet') {
    await handle.dispatch();
    taskId = handle.task.id;
  } else throw err;
}

Prevention

When it happens

Trigger: Accessing `handle.task` (or `.task.id`) on a handle returned by the background-task create function before calling `await handle.dispatch()`.

Common situations: Reading the task ID immediately after creating the handle and forgetting to dispatch; using the getter in a render/log statement before the dispatch promise resolves; assuming `create` itself enqueues the task when it only builds the handle.

Related errors


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