{"record":{"id":"4ef179764e8c08e2","repo":"mastra-ai/mastra","slug":"factory-transition-service-is-unavailable","errorCode":null,"errorMessage":"Factory transition service is unavailable.","messagePattern":"Factory transition service is unavailable\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"mastracode/factory/src/rules/start-coordinator.ts","lineNumber":231,"sourceCode":"      );\n    }\n    const prepared = await storage.prepareRunStart({\n      orgId: request.orgId,\n      userId: request.userId,\n      factoryProjectId: request.factoryProjectId,\n      workItem: { id: request.workItem.id, input: request.workItem.input },\n      role: request.workItem.role,\n      session: { sessionId: sourceSession.sessionId, branch: sourceSession.branch, threadId },\n      resourceId: sourceSession.sessionId,\n      kickoffKey: request.kickoffKey,\n      kickoffMessage,\n      armAutonomy: request.armAutonomy === true,\n    });\n    await session.thread.setSetting({ key: 'factoryWorkItemId', value: prepared.item.id });\n\n    let revision = prepared.item.revision;\n    if (prepared.item.stages.length !== 1 || prepared.item.stages[0] !== request.destinationStage) {\n      if (!this.#transitionService) throw new Error('Factory transition service is unavailable.');\n      const transition = await this.#transitionService.transition({\n        orgId: request.orgId,\n        factoryProjectId: request.factoryProjectId,\n        workItemId: prepared.item.id,\n        board: prepared.item.externalSource?.type === 'pull-request' ? 'review' : 'work',\n        stage: request.destinationStage,\n        expectedRevision: prepared.item.revision,\n        actor: { type: 'human', id: request.userId },\n        ingress: { type: 'human', identity: `start:${request.kickoffKey}:transition` },\n        cause: 'run_start',\n      });\n      if (transition.status === 'rejected') {\n        await storage.markPendingStart(prepared.binding.id, 'failed', transition.reason);\n        throw new FactoryStartTransitionError(transition);\n      }\n      revision = transition.revision;\n    }\n","sourceCodeStart":213,"sourceCodeEnd":249,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/mastracode/factory/src/rules/start-coordinator.ts#L213-L249","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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."],"exampleFix":"// before\nconst coordinator = new FactoryStartCoordinator({ storage, sessions });\n// after\nconst coordinator = new FactoryStartCoordinator({\n  storage,\n  sessions,\n  transitionService: new FactoryTransitionService({ storage, rules }),\n});","handlingStrategy":"validation","validationCode":"const transitionsEnabled =\n  coordinatorHasTransitionService(coordinator) &&\n  (prepared.item.stages.length !== 1 || prepared.item.stages[0] !== destinationStage);\nif (transitionsEnabled) throw new Error('Configure a transitionService before this kickoff.');","typeGuard":"function hasTransitionService(c: { getTransitionService?: () => unknown }): boolean {\n  return typeof c.getTransitionService === 'function' && c.getTransitionService() != null;\n}","tryCatchPattern":"try {\n  await coordinator.prepare(request);\n} catch (e) {\n  if (e instanceof Error && e.message === 'Factory transition service is unavailable.') {\n    // re-create coordinator with transitionService and retry once\n  } else throw e;\n}","preventionTips":["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."],"tags":["factory","dependency-injection","configuration","transition-service"],"backgroundTag":"missing-dependency-injection-binding","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}