mastra-ai/mastra · error · FactoryDispatchError

unsupported_provider_item

unsupported_provider_item

Error message

Factory skill invocation requires one exclusive board stage.

What it means

prepareFactoryRuleBinding maps an external work item to a factory skill invocation, and factoryRuleStage(item.stages) must yield exactly one board stage. When the item has zero or multiple stages (no exclusive stage), the binding cannot be dispatched deterministically, so a FactoryDispatchError with code 'unsupported_provider_item' is thrown.

Source

Thrown at mastracode/factory/src/routes/surface.ts:186

 * default model. Exported for tests — this is the autonomous entry point with no
 * browser and no interactive user, so nothing else would catch a regression in
 * what it forwards.
 */
export async function prepareFactoryRuleBinding(
  github: GithubIntegration,
  coordinator: Pick<FactoryStartCoordinator, 'prepare'>,
  projects: FactoryProjectsStorage,
  input: FactoryBindingPreparationInput,
): Promise<void> {
  try {
    const branch = workItemBranch({
      id: input.item.id,
      source: workItemBranchSource(input.item.externalSource),
      metadata: input.item.metadata,
    });
    const destinationStage = factoryRuleStage(input.item.stages);
    if (!destinationStage) {
      throw new FactoryDispatchError(
        'unsupported_provider_item',
        'Factory skill invocation requires one exclusive board stage.',
      );
    }
    const repositorySlug =
      typeof input.item.metadata?.repository === 'string' ? input.item.metadata.repository : undefined;
    const preparedSession = await ensureFactorySourceSession({
      sourceControl: github.sourceControlStorage,
      orgId: input.record.orgId,
      factoryProjectId: input.record.factoryProjectId,
      repositorySlug,
      branch,
      // A human-approved proposal has an interactive user: attribute the run to
      // the approver, not the repo connector.
      attributeToUserId: input.record.approvedBy ?? undefined,
    });

    await coordinator.prepare({

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Ensure the source work item is assigned to exactly one board stage before the rule triggers.
  2. Fix provider-side stage configuration so items map to a single column/stage.
  3. Add a rule filter that skips items without an exclusive stage instead of binding them.
  4. Inspect item.stages in the payload and normalize it (pick/require one) upstream of prepareFactoryRuleBinding.

Example fix

// before
await prepareFactoryRuleBinding({ item }); // throws when item.stages = []
// after
if (item.stages.length === 1) {
  await prepareFactoryRuleBinding({ item });
} else {
  logger.warn('Skipping item without exclusive stage', { id: item.id, stages: item.stages });
}
Defensive patterns

Strategy: validation

Validate before calling

function hasExclusiveStage(item: { stages: unknown[] }): boolean {
  return Array.isArray(item.stages) && item.stages.length === 1;
}
if (!hasExclusiveStage(item)) skipBinding(item);

Type guard

function isSingleStageItem(item: { stages: string[] }): item is { stages: [string] } {
  return item.stages.length === 1;
}

Try / catch

try {
  await prepareFactoryRuleBinding(input);
} catch (e) {
  if (e instanceof FactoryDispatchError && e.code === 'unsupported_provider_item') {
    logger.warn('Work item has no exclusive board stage; skipping', { id: input.item.id, stages: input.item.stages });
    return null; // skip instead of failing the whole sync
  }
  throw e;
}

Prevention

When it happens

Trigger: A provider webhook/rule fires for a work item whose stages array is empty or contains more than one stage; syncing items from a board where the card sits in multiple columns or none.

Common situations: Provider boards where items aren't assigned to a column yet (backlog-less items); misconfigured board rules attaching multiple stage labels; provider API changes returning duplicated stage memberships; custom fields mapping several stages onto one item.

Related errors


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