mastra-ai/mastra · error

Factory transition service is unavailable.

Error message

Factory transition service is unavailable.

What it means

The Factory run-start coordinator (`prepare`) throws this when the run needs a board/stage transition (the prepared work item's current stages don't already equal the requested destination stage) but no `FactoryTransitionService` was wired into the coordinator. The transition service is what performs governed, revision-checked stage moves; without it, a multi-stage kickoff cannot proceed. It signals a wiring/construction problem, not a data or authorization problem.

Source

Thrown at mastracode/factory/src/rules/start-coordinator.ts:231

      );
    }
    const prepared = await storage.prepareRunStart({
      orgId: request.orgId,
      userId: request.userId,
      factoryProjectId: request.factoryProjectId,
      workItem: { id: request.workItem.id, input: request.workItem.input },
      role: request.workItem.role,
      session: { sessionId: sourceSession.sessionId, branch: sourceSession.branch, threadId },
      resourceId: sourceSession.sessionId,
      kickoffKey: request.kickoffKey,
      kickoffMessage,
      armAutonomy: request.armAutonomy === true,
    });
    await session.thread.setSetting({ key: 'factoryWorkItemId', value: prepared.item.id });

    let revision = prepared.item.revision;
    if (prepared.item.stages.length !== 1 || prepared.item.stages[0] !== request.destinationStage) {
      if (!this.#transitionService) throw new Error('Factory transition service is unavailable.');
      const transition = await this.#transitionService.transition({
        orgId: request.orgId,
        factoryProjectId: request.factoryProjectId,
        workItemId: prepared.item.id,
        board: prepared.item.externalSource?.type === 'pull-request' ? 'review' : 'work',
        stage: request.destinationStage,
        expectedRevision: prepared.item.revision,
        actor: { type: 'human', id: request.userId },
        ingress: { type: 'human', identity: `start:${request.kickoffKey}:transition` },
        cause: 'run_start',
      });
      if (transition.status === 'rejected') {
        await storage.markPendingStart(prepared.binding.id, 'failed', transition.reason);
        throw new FactoryStartTransitionError(transition);
      }
      revision = transition.revision;
    }

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Inject a FactoryTransitionService into the StartCoordinator's constructor/options so `#transitionService` is defined.
  2. If transitions aren't needed for this flow, pick a `destinationStage` that already matches the work item's single current stage so the transition branch is skipped.
  3. Check the bootstrap/DI wiring for the factory rules package and ensure the transition service module is initialized before run start.
  4. Verify package versions: if the factory config schema changed, regenerate the wiring so transitionService is no longer omitted.

Example fix

// before
const coordinator = new FactoryStartCoordinator({ storage, sessions });
// after
const coordinator = new FactoryStartCoordinator({
  storage,
  sessions,
  transitionService: new FactoryTransitionService({ storage, rules }),
});
Defensive patterns

Strategy: validation

Validate before calling

const transitionsEnabled =
  coordinatorHasTransitionService(coordinator) &&
  (prepared.item.stages.length !== 1 || prepared.item.stages[0] !== destinationStage);
if (transitionsEnabled) throw new Error('Configure a transitionService before this kickoff.');

Type guard

function hasTransitionService(c: { getTransitionService?: () => unknown }): boolean {
  return typeof c.getTransitionService === 'function' && c.getTransitionService() != null;
}

Try / catch

try {
  await coordinator.prepare(request);
} catch (e) {
  if (e instanceof Error && e.message === 'Factory transition service is unavailable.') {
    // re-create coordinator with transitionService and retry once
  } else throw e;
}

Prevention

When it happens

Trigger: Calling `prepare` (directly or via prepared/preparePromptKickoff/triage/plan/first/replay) on a `StartCoordinator` built without `transitionService`, when the prepared item's `stages` array differs from `request.destinationStage` (i.e. the item still needs to be moved onto the destination stage before the run starts).

Common situations: Constructing the coordinator from a partial config (e.g. a lightweight/CLI bootstrap that omits DI bindings); a factory project whose transition pipeline was disabled by config; a version change where transitionService became a separate injectable and older wiring code was never updated.

Related errors


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