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
- Inject a FactoryTransitionService into the StartCoordinator's constructor/options so `#transitionService` is defined.
- 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.
- Check the bootstrap/DI wiring for the factory rules package and ensure the transition service module is initialized before run start.
- 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
- Always construct StartCoordinator via the shared factory bootstrap so DI includes transitionService.
- Add a construction-time assert that transitionService is provided when the coordinator supports multi-stage flows.
- Keep destinationStage aligned with the item's current stage when transitions are not configured.
- Add an integration test that calls prepare for a cross-stage kickoff with and without the service wired.
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
- Factory source control storage is unavailable
- ${setupError.message}. The sandbox stays usable: this setup
- storageBackend is required when injecting a custom storage i
- Weather agent not found
- Dynamic memory factory returned empty value
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/4ef179764e8c08e2.
Report an issue: GitHub.