mastra-ai/mastra · error · MastraError

SCHEDULES_MISSING_RESOURCE_ID

SCHEDULES_MISSING_RESOURCE_ID

Error message

Schedule${where}: 'resourceId' is required when 'threadId' is set.

What it means

Mastra schedules support attaching a memory thread (`threadId`) to an agent schedule, but a thread can only be resolved when its owning resource is also given via `resourceId`. When a schedule definition sets `threadId` without `resourceId`, `assertValidScheduleDefinition` in packages/core/src/schedules/define.ts:226 throws SCHEDULES_MISSING_RESOURCE_ID so the invalid pair is rejected before it is persisted. This is a user-category validation error, raised at definition time (including for Markdown-defined schedules) rather than at fire time.

Source

Thrown at packages/core/src/schedules/define.ts:226

      domain: ErrorDomain.AGENT,
      category: ErrorCategory.USER,
      details: { label: label ?? '', signalType: String(definition.signalType) },
      text: `Schedule${where}: unknown signalType "${definition.signalType}". Expected one of: ${SCHEDULE_SIGNAL_TYPES.join(', ')}.`,
    });
  }

  if (definition.status !== undefined && !SCHEDULE_STATUSES.includes(definition.status)) {
    throw new MastraError({
      id: 'SCHEDULES_INVALID_STATUS',
      domain: ErrorDomain.AGENT,
      category: ErrorCategory.USER,
      details: { label: label ?? '', status: String(definition.status) },
      text: `Schedule${where}: unknown status "${definition.status}". Expected one of: ${SCHEDULE_STATUSES.join(', ')}.`,
    });
  }

  if (definition.threadId && !definition.resourceId) {
    throw new MastraError({
      id: 'SCHEDULES_MISSING_RESOURCE_ID',
      domain: ErrorDomain.AGENT,
      category: ErrorCategory.USER,
      details: { label: label ?? '' },
      text: `Schedule${where}: 'resourceId' is required when 'threadId' is set.`,
    });
  }
}

/**
 * Encode one component of a row id so it cannot contain the `__` delimiter.
 *
 * `encodeURIComponent` leaves `_` untouched, so escaping it explicitly is what
 * actually makes the delimiter unambiguous — otherwise an agent named `a__b`
 * and one named `a` with a key starting `_b` would produce the same row id.
 * `decodeURIComponent` reverses `%5F` for free.
 */
function encodeRowIdPart(value: string): string {

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Add the matching `resourceId` (the resource that owns the thread) to the schedule definition alongside `threadId`.
  2. If the schedule should not use memory threads, remove `threadId` instead of adding a resourceId.
  3. Re-run/reload after fixing; for Markdown-defined schedules, correct the frontmatter/definition and reload the schedules.

Example fix

// before
mastra.defineSchedule({
  id: 'daily-digest',
  agentId: 'assistant',
  prompt: 'Summarize the thread',
  cron: '0 9 * * *',
  threadId: 'thread_123',
});

// after
mastra.defineSchedule({
  id: 'daily-digest',
  agentId: 'assistant',
  prompt: 'Summarize the thread',
  cron: '0 9 * * *',
  threadId: 'thread_123',
  resourceId: 'user_42',
});
Defensive patterns

Strategy: validation

Validate before calling

function canDefineSchedule(def) {
  return !(def.threadId && !def.resourceId);
}
if (!canDefineSchedule(def)) {
  throw new Error('resourceId is required when threadId is set');
}

Type guard

function hasResourceForThread(def): def is typeof def & { resourceId: string } {
  return !def.threadId || typeof def.resourceId === 'string' && def.resourceId.length > 0;
}

Try / catch

import { MastraError } from '@mastra/core/error';
try {
  mastra.defineSchedule(def);
} catch (e) {
  if (e instanceof MastraError && e.id === 'SCHEDULES_MISSING_RESOURCE_ID') {
    console.error(`Schedule ${e.details?.label}: add resourceId or remove threadId`);
  } else throw e;
}

Prevention

When it happens

Trigger: Calling `mastra.getSchedule(...)`/`defineSchedule` (or `resolveSchedules`) with a definition object containing a truthy `threadId` and an undefined/empty `resourceId`, e.g. `{ agentId, prompt, cron: '0 9 * * *', threadId: 'thread_123' }` with no `resourceId`.

Common situations: Copy-pasting a schedule config that mentions threadId but omitting resourceId; wiring memory threads to scheduled agent prompts and assuming threadId alone identifies the thread; partially migrating configs where resourceId was added later; Markdown/YAML schedule files that only got the threadId field filled in.

Understand the failure class

Background: "Missing required field" and "field is required" errors: why libraries reject payloads that omit mandatory fields — this error's family across 20 libraries.

Related errors


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