mastra-ai/mastra · error

Notification ${current.id} is missing agentId

Error message

Notification ${current.id} is missing agentId

What it means

sendNotificationRecord re-reads a notification from storage and delivers it to its agent. This error is thrown when the persisted notification record has no `agentId`, which is mandatory because the dispatcher needs it to resolve the target agent via mastra.getAgentById. It indicates a corrupted or hand-crafted notification record in storage.

Source

Thrown at packages/core/src/notifications/dispatcher.ts:142

  });
}

async function sendNotificationRecord({
  mastra,
  storage,
  record,
  now,
  batchThreadState,
}: {
  mastra: Mastra;
  storage: NotificationsStorage;
  record: NotificationRecord;
  now: Date;
  batchThreadState?: NotificationDeliveryThreadState;
}): Promise<{ record: NotificationRecord; signal: CreatedAgentSignal } | null> {
  const current = await storage.getNotification({ threadId: record.threadId, id: record.id });
  if (!current || current.status !== 'pending' || current.deliveredSignalId) return null;
  if (!current.agentId) throw new Error(`Notification ${current.id} is missing agentId`);
  if (!current.resourceId) throw new Error(`Notification ${current.id} is missing resourceId`);

  const agent = (await mastra.getAgentById(current.agentId as never)) as NotificationDispatchAgent;
  const threadState =
    batchThreadState ??
    agentThreadStreamRuntime.getThreadState(
      { resourceId: current.resourceId, threadId: current.threadId },
      agent.getPubSub?.(),
    );
  if (current.priority === 'high' && current.summarySignalId && threadState === 'active') return null;

  const signal = createNotificationSignal({
    ...current,
    status: 'delivered',
    deliveredAt: now,
    lastDeliveryAttemptAt: now,
  });
  const streamOptions = await resolveIfIdleStreamOptions(mastra, agent, { record: current, threadState, now });

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Inspect the offending record (storage.getNotification with its id/threadId) and re-create it through the official notification API so agentId is populated.
  2. Backfill agentId on affected rows in your storage (UPDATE notifications SET agentId = ... WHERE agentId IS NULL) for records that are still 'pending'.
  3. If the record is invalid and obsolete, delete it or mark it failed so the dispatcher skips it.
  4. Upgrade mastra / fix any custom storage adapter that silently drops agentId on write.

Example fix

// before (hand-inserted record)
await storage.saveNotification({ id: 'n1', threadId: 't1', resourceId: null, status: 'pending' });
// after
await storage.saveNotification({ id: 'n1', threadId: 't1', agentId: 'my-agent', resourceId: 'user-1', status: 'pending' });
Defensive patterns

Strategy: try-catch

Validate before calling

const rec = await storage.getNotification({ threadId, id });
if (rec && rec.status === 'pending' && !rec.agentId) {
  logger.warn('Skipping notification with missing agentId', { id });
  await storage.updateNotification({ id, threadId, status: 'failed', lastDeliveryError: 'missing agentId' });
}

Type guard

function isDeliverable(rec: NotificationRecord | null): rec is NotificationRecord & { agentId: string; resourceId: string } {
  return !!rec && rec.status === 'pending' && typeof rec.agentId === 'string' && typeof rec.resourceId === 'string';
}

Try / catch

try {
  await dispatchNotifications(mastra, storage, records, now);
} catch (err) {
  if (err instanceof Error && /is missing agentId/.test(err.message)) {
    const id = /Notification (.+) is missing agentId/.exec(err.message)?.[1];
    logger.error('Corrupt notification record, marking failed', { id, err });
    await storage.updateNotification({ id, threadId, status: 'failed', lastDeliveryError: err.message });
  } else {
    throw err;
  }
}

Prevention

When it happens

Trigger: The dispatcher attempts delivery of a pending, not-yet-delivered notification whose stored record (returned by storage.getNotification) has a missing/empty agentId — typically a record created outside the normal notification-creation API or written by an older/buggy version.

Common situations: Manually inserting notification rows into the storage backend; a migration or older mastra version writing records without agentId; custom storage adapters that drop the agentId field; deleting/renaming agents and then patching stored records by hand.

Related errors


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